<?php

use App\Enums\CampaignStatus;
use App\Enums\CreditType;
use App\Models\Ad;
use App\Models\Group;
use App\Models\Kategori;

use function Pest\Laravel\actingAs;

beforeEach(function () {
    Group::firstOrCreate(['name' => Group::ADMIN]);
    Group::firstOrCreate(['name' => Group::MEMBERS]);
});

test('member can create campaign without upfront credit deduction', function () {
    $member = makeMemberWithCredit(1000);
    $kategori = Kategori::factory()->create();

    $response = actingAs($member)->post(route('campaigns.store'), [
        'judul' => 'Iklan Demo',
        'url' => 'https://example.com',
        'jam_tayang_mulai' => '08:00',
        'jam_tayang_selesai' => '20:00',
        'budget_harian' => 100000,
        'kategori_ids' => [$kategori->id],
    ]);

    $response->assertRedirect(route('campaigns.index'));

    $member->refresh();
    $ad = Ad::first();

    // Model budget harian: tidak ada debit upfront, saldo tetap.
    expect($member->credit)->toBe(1000)
        ->and($ad->status)->toBe(CampaignStatus::Pending)
        ->and($ad->budget_harian)->toBe(100000)
        ->and($ad->credit)->toBe(0)
        ->and($ad->user_id)->toBe($member->id);

    // Tidak ada mutasi Out di credit history.
    $mutation = $member->creditHistory()->where('jenis', CreditType::Out)->first();
    expect($mutation)->toBeNull();
});

test('member with zero saldo cannot create campaign', function () {
    $member = makeMemberWithCredit(0); // saldo 0
    $kategori = Kategori::factory()->create();

    $response = actingAs($member)->post(route('campaigns.store'), [
        'judul' => 'Iklan Besar',
        'url' => 'https://example.com',
        'jam_tayang_mulai' => '08:00',
        'jam_tayang_selesai' => '20:00',
        'budget_harian' => 500000,
        'kategori_ids' => [$kategori->id],
    ]);

    $response->assertSessionHas('error');
    expect(Ad::count())->toBe(0)
        ->and($member->fresh()->credit)->toBe(0); // unchanged
});


test('admin can approve a pending campaign', function () {
    $admin = makeAdmin();
    $member = makeMemberWithCredit(1000);
    $kategori = Kategori::factory()->create();

    $ad = Ad::factory()->create([
        'user_id' => $member->id,
        'budget_harian' => 100000,
        'status' => CampaignStatus::Pending,
    ]);
    attachKategori($ad, $kategori);

    actingAs($admin)->get(route('campaigns.approve', $ad))->assertRedirect(route('campaigns.index'));

    $ad->refresh();
    expect($ad->status)->toBe(CampaignStatus::Aktif)
        ->and($ad->tgl_aktif)->not->toBeNull();
});

test('converting an active campaign to draft keeps saldo unchanged', function () {
    $admin = makeAdmin();
    $member = makeMemberWithCredit(1000);
    $kategori = Kategori::factory()->create();

    $ad = Ad::factory()->create([
        'user_id' => $member->id,
        'budget_harian' => 100000,
        'klik' => 50,
        'status' => CampaignStatus::Aktif,
    ]);
    attachKategori($ad, $kategori);

    actingAs($admin)->get(route('campaigns.draft', $ad))->assertRedirect(route('campaigns.index'));

    $ad->refresh();
    $member->refresh();

    expect($ad->status)->toBe(CampaignStatus::Draft)
        ->and($member->credit)->toBe(1000); // unchanged — budget harian, tidak ada locked credit
});

test('restoring a draft campaign sets it active again', function () {
    $admin = makeAdmin();
    $member = makeMemberWithCredit(1000);
    $kategori = Kategori::factory()->create();

    $ad = Ad::factory()->draft()->create([
        'user_id' => $member->id,
        'budget_harian' => 100000,
        'klik' => 50,
        'tgl_aktif' => null,
    ]);
    attachKategori($ad, $kategori);

    actingAs($admin)->get(route('campaigns.restore', $ad))->assertRedirect(route('campaigns.index'));

    $ad->refresh();
    expect($ad->status)->toBe(CampaignStatus::Aktif)
        ->and($ad->tgl_aktif)->not->toBeNull()
        ->and($ad->is_paused)->toBeFalse();
});

test('deleting a campaign does not refund (budget is daily, debited per-click)', function () {
    $admin = makeAdmin();
    $member = makeMemberWithCredit(1000);
    $kategori = Kategori::factory()->create();

    $ad = Ad::factory()->draft()->create([
        'user_id' => $member->id,
        'budget_harian' => 100000,
        'klik' => 50,
    ]);
    attachKategori($ad, $kategori);

    actingAs($admin)->delete(route('campaigns.destroy', $ad))->assertRedirect(route('campaigns.index'));

    $member->refresh();
    expect(Ad::find($ad->id))->toBeNull()
        ->and($member->credit)->toBe(1000); // unchanged — tidak ada refund

    $refund = $member->creditHistory()->where('jenis', CreditType::In)->first();
    expect($refund)->toBeNull();
});

test('member can only edit their own pending campaign', function () {
    $member = makeMemberWithCredit(1000);
    $other = makeMemberWithCredit(1000);
    $kategori = Kategori::factory()->create();

    $ownAd = Ad::factory()->create([
        'user_id' => $member->id, 'status' => CampaignStatus::Pending,
    ]);
    attachKategori($ownAd, $kategori);

    $otherAd = Ad::factory()->create([
        'user_id' => $other->id, 'status' => CampaignStatus::Pending,
    ]);
    attachKategori($otherAd, $kategori);

    // Own pending — OK
    actingAs($member)->get(route('campaigns.edit', $ownAd))->assertOk();

    // Other's campaign — redirected
    actingAs($member)->get(route('campaigns.edit', $otherAd))->assertRedirect(route('campaigns.index'));
});

test('member cannot approve campaigns', function () {
    $member = makeMemberWithCredit(1000);
    $kategori = Kategori::factory()->create();
    $ad = Ad::factory()->create([
        'user_id' => $member->id, 'status' => CampaignStatus::Pending,
    ]);
    attachKategori($ad, $kategori);

    actingAs($member)->get(route('campaigns.approve', $ad));

    expect($ad->fresh()->status)->toBe(CampaignStatus::Pending); // unchanged
});
