<?php

namespace Tests\Unit;

use App\Models\Coupon;
use App\Services\CouponCodePool;
use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
use Tests\TestCase;

class CouponCodePoolTest extends TestCase
{
    use LazilyRefreshDatabase;

    private string $codesPath;

    protected function setUp(): void
    {
        parent::setUp();

        $this->codesPath = tempnam(sys_get_temp_dir(), 'codes_');
        file_put_contents($this->codesPath, "1_AAAA\n2_BBBB\n3_CCCC\n");
    }

    protected function tearDown(): void
    {
        if (is_file($this->codesPath)) {
            unlink($this->codesPath);
        }

        parent::tearDown();
    }

    public function test_all_codes_loads_from_file(): void
    {
        $pool = new CouponCodePool($this->codesPath);

        $this->assertSame(['1_AAAA', '2_BBBB', '3_CCCC'], $pool->allCodes());
    }

    public function test_available_codes_excludes_used_coupons(): void
    {
        Coupon::factory()->create(['code' => '1_AAAA', 'phone' => '61111111']);

        $pool = new CouponCodePool($this->codesPath);

        $this->assertEqualsCanonicalizing(['2_BBBB', '3_CCCC'], $pool->availableCodes());
    }

    public function test_pick_random_returns_only_unused_code(): void
    {
        Coupon::factory()->create(['code' => '2_BBBB', 'phone' => '61111111']);

        $pool = new CouponCodePool($this->codesPath);

        for ($i = 0; $i < 20; $i++) {
            $picked = $pool->pickRandom();
            $this->assertContains($picked, ['1_AAAA', '3_CCCC']);
        }
    }

    public function test_has_available_is_false_when_all_codes_used(): void
    {
        Coupon::factory()->create(['code' => '1_AAAA', 'phone' => '61111111']);
        Coupon::factory()->create(['code' => '2_BBBB', 'phone' => '62222222']);
        Coupon::factory()->create(['code' => '3_CCCC', 'phone' => '63333333']);

        $pool = new CouponCodePool($this->codesPath);

        $this->assertFalse($pool->hasAvailable());
        $this->assertNull($pool->pickRandom());
        $this->assertSame([], $pool->availableCodes());
    }
}
