<?php

use App\Models\Currency;
use App\Models\OddsItem;
use App\Models\PlayType;
use App\Models\AdminUser;
use App\Models\JackpotPool;
use App\Models\OddsVersion;
use App\Lottery\ConfigVersionStatus;
use Database\Seeders\CurrencySeeder;
use Illuminate\Support\Facades\Hash;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

beforeEach(function (): void {
    $this->seed(CurrencySeeder::class);
});

function mintCurrencyAdminToken(): string
{
    $admin = AdminUser::query()->create([
        'username' => 'currency_admin',
        'name' => 'Currency Admin',
        'email' => null,
        'password' => Hash::make('secret-strong'),
        'status' => 0,
    ]);
    grantSuperAdminRole($admin);

    return $admin->createToken('test', ['*'], now()->addDay())->plainTextToken;
}

test('admin can list currencies', function (): void {
    $token = mintCurrencyAdminToken();

    $this->withHeader('Authorization', 'Bearer '.$token)
        ->getJson('/api/v1/admin/currencies')
        ->assertOk()
        ->assertJsonPath('data.items.0.code', 'NPR');
});

test('admin can create currency and normalize code', function (): void {
    $token = mintCurrencyAdminToken();

    $this->withHeader('Authorization', 'Bearer '.$token)
        ->postJson('/api/v1/admin/currencies', [
            'code' => 'eur',
            'name' => 'Euro',
            'is_enabled' => true,
            'is_bettable' => true,
        ])
        ->assertStatus(201)
        ->assertJsonPath('data.code', 'EUR')
        ->assertJsonPath('data.decimal_places', 2)
        ->assertJsonPath('data.is_bettable', true);

    $this->assertDatabaseHas('currencies', [
        'code' => 'EUR',
        'name' => 'Euro',
        'is_enabled' => true,
        'is_bettable' => true,
    ]);
});

test('disabling currency forces bettable off', function (): void {
    $token = mintCurrencyAdminToken();
    $currency = Currency::query()->where('code', 'USD')->firstOrFail();

    $this->withHeader('Authorization', 'Bearer '.$token)
        ->putJson('/api/v1/admin/currencies/'.$currency->code, [
            'is_enabled' => false,
            'is_bettable' => true,
        ])
        ->assertOk()
        ->assertJsonPath('data.is_enabled', false)
        ->assertJsonPath('data.is_bettable', false);

    $currency->refresh();
    expect($currency->is_enabled)->toBeFalse()
        ->and($currency->is_bettable)->toBeFalse();
});

test('enabling currency as bettable bootstraps odds items and jackpot pool', function (): void {
    $token = mintCurrencyAdminToken();
    $currency = Currency::query()->where('code', 'USD')->firstOrFail();

    PlayType::query()->create([
        'play_code' => 'STRAIGHT',
        'category' => '4d',
        'dimension' => 4,
        'bet_mode' => 'single',
        'display_name' => '直选',
        'is_enabled' => true,
        'sort_order' => 10,
        'supports_multi_number' => false,
        'reserved_rule_json' => null,
    ]);

    $version = OddsVersion::query()->create([
        'version_no' => 1,
        'status' => ConfigVersionStatus::Active->value,
        'updated_by' => null,
        'reason' => 'seed',
    ]);

    OddsItem::query()->create([
        'version_id' => $version->id,
        'play_code' => 'STRAIGHT',
        'prize_scope' => 'first',
        'odds_value' => 250000,
        'rebate_rate' => 0.05,
        'commission_rate' => 0.01,
        'currency_code' => 'NPR',
        'extra_config_json' => ['sample' => true],
    ]);

    JackpotPool::query()->updateOrCreate([
        'currency_code' => 'NPR',
    ], [
        'current_amount' => 12345,
        'contribution_rate' => '0.0300',
        'trigger_threshold' => 200000000,
        'payout_rate' => '0.4000',
        'force_trigger_draw_gap' => 88,
        'min_bet_amount' => 200,
        'combo_trigger_play_codes' => ['STRAIGHT'],
        'status' => 1,
        'last_trigger_draw_id' => null,
    ]);

    $this->withHeader('Authorization', 'Bearer '.$token)
        ->putJson('/api/v1/admin/currencies/'.$currency->code, [
            'is_bettable' => true,
        ])
        ->assertOk()
        ->assertJsonPath('data.is_bettable', true);

    $currency->refresh();
    expect($currency->is_bettable)->toBeTrue();

    $this->assertDatabaseHas('jackpot_pools', [
        'currency_code' => 'USD',
        'current_amount' => 0,
        'contribution_rate' => '0.0300',
        'trigger_threshold' => 200000000,
        'payout_rate' => '0.4000',
        'force_trigger_draw_gap' => 88,
        'min_bet_amount' => 200,
        'status' => 1,
    ]);

    $this->assertDatabaseHas('odds_items', [
        'version_id' => $version->id,
        'play_code' => 'STRAIGHT',
        'prize_scope' => 'first',
        'currency_code' => 'USD',
        'odds_value' => 250000,
    ]);

    $this->assertDatabaseHas('odds_items', [
        'version_id' => $version->id,
        'play_code' => 'STRAIGHT',
        'prize_scope' => 'second',
        'currency_code' => 'USD',
    ]);
});

test('cannot delete currency referenced by admin site default currency', function (): void {
    $token = mintCurrencyAdminToken();

    Currency::query()->create([
        'code' => 'EUR',
        'name' => 'Euro',
        'decimal_places' => 2,
        'is_enabled' => true,
        'is_bettable' => false,
    ]);

    DB::table('admin_sites')
        ->where('is_default', true)
        ->update(['currency_code' => 'EUR']);

    $this->withHeader('Authorization', 'Bearer '.$token)
        ->deleteJson('/api/v1/admin/currencies/EUR')
        ->assertStatus(422)
        ->assertJsonPath('data.references.0', '站点默认币种');

    $this->assertDatabaseHas('currencies', [
        'code' => 'EUR',
    ]);
});
