<?php

use App\Models\Currency;
use App\Models\OddsItem;
use App\Models\PlayType;
use App\Models\BetProvider;
use App\Models\OddsVersion;
use App\Models\PlayConfigItem;
use App\Models\PlayConfigVersion;
use App\Support\OddsStandardScopes;
use App\Lottery\ConfigVersionStatus;
use App\Services\Ticket\PlayCatalogResolver;
use Database\Seeders\CurrencySeeder;
use Database\Seeders\PlayTypeSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

test('syncMissingForVersion adds five scopes from default-only rows', function (): void {
    $this->seed(CurrencySeeder::class);
    $this->seed(PlayTypeSeeder::class);

    $currency = Currency::query()->where('is_bettable', true)->where('is_enabled', true)->orderBy('code')->firstOrFail();

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

    foreach (PlayType::query()->orderBy('play_code')->get() as $pt) {
        OddsItem::query()->create([
            'version_id' => $version->id,
            'provider_code' => 'GLOBAL',
            'play_code' => $pt->play_code,
            'prize_scope' => 'default',
            'odds_value' => 19_500,
            'rebate_rate' => 0.01,
            'commission_rate' => 0,
            'currency_code' => $currency->code,
            'extra_config_json' => null,
        ]);
    }

    OddsStandardScopes::syncMissingForVersion($version);

    $playCount = PlayType::query()->count();
    expect(OddsItem::query()->where('version_id', $version->id)->count())->toBe(
        $playCount * (1 + count(OddsStandardScopes::SCOPE_KEYS)),
    );
    foreach (PlayType::query()->get() as $pt) {
        foreach (OddsStandardScopes::SCOPE_KEYS as $scope) {
            $row = OddsItem::query()
                ->where('version_id', $version->id)
                ->where('play_code', $pt->play_code)
                ->where('currency_code', $currency->code)
                ->where('prize_scope', $scope)
                ->firstOrFail();

            expect((int) $row->odds_value)->toBe(OddsStandardScopes::PRESET_ODDS_BY_SCOPE[$scope]);
            /** @var string $rebate Eloquent `decimal:4` cast */
            $rebate = (string) $row->rebate_rate;
            expect($rebate)->toBe('0.0100');
        }
    }
});

test('syncMissingForVersion keeps provider-specific odds rows separate', function (): void {
    $this->seed(CurrencySeeder::class);
    $this->seed(PlayTypeSeeder::class);

    $currency = Currency::query()->where('is_bettable', true)->where('is_enabled', true)->orderBy('code')->firstOrFail();
    $play = PlayType::query()->orderBy('play_code')->firstOrFail();

    BetProvider::query()->create([
        'code' => 'MY',
        'name' => 'Malaysia',
        'is_enabled' => true,
        'sort_order' => 2,
    ]);

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

    OddsItem::query()->create([
        'version_id' => $version->id,
        'provider_code' => 'MY',
        'play_code' => $play->play_code,
        'prize_scope' => 'first',
        'dimension' => $play->dimension,
        'odds_value' => 88_000,
        'rebate_rate' => 0,
        'commission_rate' => 0,
        'currency_code' => $currency->code,
        'extra_config_json' => null,
    ]);

    OddsStandardScopes::syncMissingForVersion($version);

    foreach (OddsStandardScopes::SCOPE_KEYS as $scope) {
        $this->assertDatabaseHas('odds_items', [
            'version_id' => $version->id,
            'provider_code' => 'MY',
            'play_code' => $play->play_code,
            'currency_code' => $currency->code,
            'prize_scope' => $scope,
        ]);
    }
});

test('play catalog resolver uses provider odds and falls back to global scopes', function (): void {
    $this->seed(CurrencySeeder::class);
    $this->seed(PlayTypeSeeder::class);

    $currency = Currency::query()->where('is_bettable', true)->where('is_enabled', true)->orderBy('code')->firstOrFail();
    $play = PlayType::query()->where('play_code', 'big')->firstOrFail();

    BetProvider::query()->create([
        'code' => 'MY',
        'name' => 'Malaysia',
        'is_enabled' => true,
        'sort_order' => 2,
    ]);

    $playVersion = PlayConfigVersion::query()->create([
        'version_no' => 1,
        'status' => ConfigVersionStatus::Active->value,
        'effective_at' => now(),
        'updated_by' => null,
        'reason' => 'play',
    ]);
    PlayConfigItem::query()->create([
        'version_id' => $playVersion->id,
        'play_code' => $play->play_code,
        'category' => $play->category,
        'dimension' => $play->dimension,
        'bet_mode' => $play->bet_mode,
        'display_name' => $play->display_name ?? $play->play_code,
        'is_enabled' => true,
        'min_bet_amount' => 100,
        'max_bet_amount' => 1_000_000,
        'display_order' => $play->sort_order,
        'supports_multi_number' => $play->supports_multi_number,
        'reserved_rule_json' => null,
    ]);

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

    foreach (OddsStandardScopes::SCOPE_KEYS as $scope) {
        OddsItem::query()->create([
            'version_id' => $oddsVersion->id,
            'provider_code' => 'GLOBAL',
            'play_code' => $play->play_code,
            'prize_scope' => $scope,
            'dimension' => $play->dimension,
            'odds_value' => 10_000,
            'rebate_rate' => 0,
            'commission_rate' => 0,
            'currency_code' => $currency->code,
            'extra_config_json' => null,
        ]);
    }
    OddsItem::query()->create([
        'version_id' => $oddsVersion->id,
        'provider_code' => 'MY',
        'play_code' => $play->play_code,
        'prize_scope' => 'first',
        'dimension' => $play->dimension,
        'odds_value' => 99_000,
        'rebate_rate' => 0,
        'commission_rate' => 0,
        'currency_code' => $currency->code,
        'extra_config_json' => null,
    ]);

    $resolved = app(PlayCatalogResolver::class)->resolve($play->play_code, $currency->code, 'MY');
    $first = $resolved['odds_items']->firstWhere('prize_scope', 'first');
    $second = $resolved['odds_items']->firstWhere('prize_scope', 'second');

    expect((int) $first->odds_value)->toBe(99_000)
        ->and((string) $first->provider_code)->toBe('MY')
        ->and((int) $second->odds_value)->toBe(10_000)
        ->and((string) $second->provider_code)->toBe('GLOBAL');
});
