<?php

use App\Enums\CampaignStatus;
use App\Enums\KategoriJenis;
use App\Models\Ad;
use App\Models\AdsPlacement;
use App\Models\IpHistory;
use App\Models\Kategori;
use App\Models\User;

beforeEach(function () {
    // Default placement UNKNOWN (id=1).
    AdsPlacement::firstOrCreate(
        ['id' => AdsPlacement::DEFAULT_ID],
        ['kode' => AdsPlacement::DEFAULT_KODE, 'keterangan' => 'Default']
    );
});

function aktifAd(Kategori $kategori, int $credit = 100, int $klik = 0): Ad
{
    $user = User::factory()->create(['credit' => $credit]);

    $ad = Ad::factory()->active()->create([
        'user_id' => $user->id,
        'budget_harian' => $credit * 100, // rate 100 → cap = credit klik/hari
        'klik' => $klik,
        'url' => 'https://target.example.com',
    ]);

    return attachKategori($ad, $kategori);
}

test('redirect kategori goes straight to landing/go and records a click', function () {
    $kategori = Kategori::factory()->create(['alias' => 'redirect1', 'jenis' => KategoriJenis::Redirect]);
    $ad = aktifAd($kategori, credit: 100);

    $response = $this->get(route('landing.show', ['alias' => 'redirect1']));

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

    $ad->refresh();
    expect($ad->klik)->toBe(1)
        ->and($ad->muncul)->toBe(1) // impression tercatat saat rotator menampilkan ad
        ->and(IpHistory::count())->toBe(1);
});

test('landing page kategori renders interstitial page', function () {
    $kategori = Kategori::factory()->create(['alias' => 'landing1', 'jenis' => KategoriJenis::LandingPage]);
    $ad = aktifAd($kategori);

    $response = $this->get(route('landing.show', ['alias' => 'landing1']));

    $response->assertOk();
    $response->assertInertia(fn ($page) => $page->component('Landing/Index'));

    // Klik belum tercatat (belum tekan tombol "go"), tapi tayang sudah.
    expect($ad->fresh()->klik)->toBe(0)
        ->and($ad->fresh()->muncul)->toBe(1);
});

test('landing/go records click and increments ad.klik', function () {
    $kategori = Kategori::factory()->create(['alias' => 'go1', 'jenis' => KategoriJenis::Redirect]);
    $ad = aktifAd($kategori);

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

    expect($ad->fresh()->klik)->toBe(1);
});

test('anti-fraud: same IP cannot click same ad twice in one day', function () {
    $kategori = Kategori::factory()->create(['alias' => 'fraud1', 'jenis' => KategoriJenis::Redirect]);
    $ad = aktifAd($kategori, credit: 100);

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

    expect($ad->fresh()->klik)->toBe(1) // tetap 1, klik kedua ditolak
        ->and(IpHistory::count())->toBe(1);
});

test('ad pauses with daily_cap when daily budget cap reached', function () {
    $kategori = Kategori::factory()->create(['alias' => 'expire1', 'jenis' => KategoriJenis::Redirect]);
    $ad = aktifAd($kategori, credit: 2); // cap = 2 klik/hari
    // Pre-set cap sudah tercapai (2 klik) — klik berikutnya pause.
    $ad->update(['klik_hari_ini' => 2, 'klik_tanggal' => today()]);

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

    $ad->refresh();
    expect($ad->is_paused)->toBeTrue()
        ->and($ad->pause_reason)->toBe('daily_cap')
        ->and($ad->klik_hari_ini)->toBe(2); // tidak increment (pause duluan)
});

test('unknown alias redirects to default url', function () {
    config()->set('ads.default_url', 'https://default.example.com');

    $response = $this->get(route('landing.show', ['alias' => 'tidak-ada']));

    $response->assertRedirect('https://default.example.com');
});

test('no active ad redirects to default url', function () {
    config()->set('ads.default_url', 'https://default.example.com');
    $kategori = Kategori::factory()->create(['alias' => 'empty1', 'jenis' => KategoriJenis::Redirect]);
    // Tidak ada iklan aktif untuk kategori ini.

    $response = $this->get(route('landing.show', ['alias' => 'empty1']));

    $response->assertRedirect('https://default.example.com');
});

test('rotator serves ads sequentially by id (1,2,3 then repeat)', function () {
    $kategori = Kategori::factory()->create(['alias' => 'least1', 'jenis' => KategoriJenis::Redirect]);

    $ad1 = aktifAd($kategori, credit: 100);
    $ad2 = aktifAd($kategori, credit: 100);
    $ad3 = aktifAd($kategori, credit: 100);
    $ad1->update(['url' => 'https://target1.example.com']);
    $ad2->update(['url' => 'https://target2.example.com']);
    $ad3->update(['url' => 'https://target3.example.com']);

    // Pointer maju per tayang: urut id naik lalu wrap ke awal.
    $picked = [];
    for ($i = 0; $i < 5; $i++) {
        $response = $this->get(route('landing.show', ['alias' => 'least1']));
        $response->assertRedirect();
        $picked[] = Ad::where('url', $response->headers->get('Location'))->value('id');
    }

    expect($picked)->toBe([$ad1->id, $ad2->id, $ad3->id, $ad1->id, $ad2->id]);
});

test('rotator alternates ads by daily impressions (landing page, no clicks)', function () {
    $kategori = Kategori::factory()->create(['alias' => 'alt1', 'jenis' => KategoriJenis::LandingPage]);

    $adA = aktifAd($kategori, credit: 100);
    $adB = aktifAd($kategori, credit: 100);
    $adA->update(['judul' => 'Ad A']);
    $adB->update(['judul' => 'Ad B']);

    $picked = [];
    for ($i = 0; $i < 4; $i++) {
        $response = $this->get(route('landing.show', ['alias' => 'alt1']));
        $response->assertOk();
        $picked[] = $response->original->getData()['page']['props']['ad']['id'];
    }

    // Kedua ad harus kebagian tayang bergantian (tidak satu ad menang terus).
    expect($picked)->toBe([$adA->id, $adB->id, $adA->id, $adB->id])
        ->and($adA->fresh()->muncul_hari_ini)->toBe(2)
        ->and($adB->fresh()->muncul_hari_ini)->toBe(2);
});

test('kategori viewed counter increments on access', function () {
    $kategori = Kategori::factory()->create(['alias' => 'view1', 'jenis' => KategoriJenis::Redirect, 'viewed' => 0]);
    aktifAd($kategori);

    $this->get(route('landing.show', ['alias' => 'view1']));

    expect($kategori->fresh()->viewed)->toBe(1);
});
