<?php

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

use function Pest\Laravel\actingAs;

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

/**
 * Helper: buat ad Aktif + user dengan saldo, kategori punya alias.
 */
function makeClickableAd(int $credit = 100, int $budgetHarian = 10000): array
{
    $member = makeMemberWithCredit($credit);
    $kategori = Kategori::factory()->create(['alias' => 'test-alias', 'jenis' => 'Redirect']);

    $ad = Ad::factory()->active()->create([
        'user_id' => $member->id,
        'budget_harian' => $budgetHarian,
        'is_paused' => false,
        'pause_reason' => null,
    ]);
    attachKategori($ad, $kategori);

    return [$member, $kategori, $ad];
}

test('a valid click debits 1 credit from saldo and records mutation', function () {
    [$member, $kategori, $ad] = makeClickableAd(credit: 100, budgetHarian: 10000);
    // rate 100 → cap = 10000/100 = 100 klik/hari.

    $response = actingAs($member)->get(route('landing.go', $ad));

    $response->assertRedirect($ad->url);

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

    expect($ad->klik)->toBe(1)
        ->and($ad->klik_hari_ini)->toBe(1)
        ->and($member->credit)->toBe(99); // 100 - 1

    $mutation = $member->creditHistory()->where('jenis', CreditType::Out)->first();
    expect($mutation)->not->toBeNull()
        ->and($mutation->credit)->toBe(1);
});

test('click after daily cap pauses campaign with daily_cap reason', function () {
    [$member, $kategori, $ad] = makeClickableAd(credit: 100, budgetHarian: 10000);
    // cap = 100. Pre-set klik_hari_ini = 100 (cap tercapai).
    $ad->update(['klik_hari_ini' => 100, 'klik_tanggal' => today()]);

    actingAs($member)->get(route('landing.go', $ad))->assertRedirect($ad->url);

    $ad->refresh();
    expect($ad->is_paused)->toBeTrue()
        ->and($ad->pause_reason)->toBe('daily_cap');
});

test('click with zero saldo pauses campaign with no_saldo reason', function () {
    [$member, $kategori, $ad] = makeClickableAd(credit: 0, budgetHarian: 10000);
    // saldo 0 → tidak bisa debit.

    actingAs($member)->get(route('landing.go', $ad))->assertRedirect($ad->url);

    $ad->refresh();
    expect($ad->is_paused)->toBeTrue()
        ->and($ad->pause_reason)->toBe('no_saldo')
        ->and($ad->klik)->toBe(0); // tidak catat klik
});

test('double click from same IP same day does not double-debit', function () {
    [$member, $kategori, $ad] = makeClickableAd(credit: 100, budgetHarian: 10000);

    actingAs($member)->get(route('landing.go', $ad));
    actingAs($member)->get(route('landing.go', $ad));

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

    // Hanya 1 klik tercatat (anti-fraud 1 IP/ad/hari).
    expect($ad->klik)->toBe(1)
        ->and($member->credit)->toBe(99);
});

test('new day settlement clears daily_cap pause and rolls over unused budget', function () {
    [$member, $kategori, $ad] = makeClickableAd(credit: 100, budgetHarian: 10000);
    // cap = 100. Hari kemarin pakai 60, sisa 40 harus roll.
    $yesterday = today()->subDay()->toDateString();
    $ad->update([
        'klik_hari_ini' => 60,
        'klik_tanggal' => $yesterday,
        'is_paused' => true,
        'pause_reason' => 'daily_cap',
    ]);

    // Trigger klik hari ini → lazy-settle di go().
    actingAs($member)->get(route('landing.go', $ad));

    $ad->refresh();
    // rollover = min(base_cap=100, unused=40) = 40.
    expect($ad->klik_hari_ini)->toBe(1) // reset lalu klik pertama hari ini
        ->and($ad->rollover_klik)->toBe(40)
        ->and($ad->is_paused)->toBeFalse() // daily_cap cleared
        ->and($ad->pause_reason)->toBeNull();
});
