<?php

namespace Database\Seeders;

use App\Models\Currency;
use App\Models\OddsItem;
use App\Models\PlayType;
use App\Models\OddsVersion;
use App\Models\PlayConfigItem;
use Illuminate\Database\Seeder;
use App\Models\PlayConfigVersion;
use Illuminate\Support\Facades\DB;
use App\Support\OddsStandardScopes;
use App\Lottery\ConfigVersionStatus;

/**
 * 将「玩法目录」与已存在的玩法配置 / 赔率版本对齐（幂等，可反复执行）。
 *
 * 典型场景：`play_types` 已扩展，但某条 active/draft 的 `play_config_items` 或 `odds_items`
 * 仍是早期子集，后台出现大量「无配置行」或赔率缺档。
 *
 * 执行：php artisan db:seed --class=PlayOperationalAlignmentSeeder
 */
final class PlayOperationalAlignmentSeeder extends Seeder
{
    private const MIN_BET = 100;

    private const MAX_BET = 500_000_000;

    public function run(): void
    {
        $this->call(PlayTypeSeeder::class);

        DB::transaction(function (): void {
            $open = [ConfigVersionStatus::Active->value, ConfigVersionStatus::Draft->value];

            foreach (PlayConfigVersion::query()->whereIn('status', $open)->orderBy('id')->cursor() as $version) {
                $this->syncPlayConfigItems($version);
            }

            foreach (OddsVersion::query()->whereIn('status', $open)->orderBy('id')->cursor() as $version) {
                $this->syncOddsItemsForAllPlayTypes($version);
            }
        });
    }

    private function syncPlayConfigItems(PlayConfigVersion $version): void
    {
        $vid = (int) $version->id;
        $existing = PlayConfigItem::query()
            ->where('version_id', $vid)
            ->pluck('play_code')
            ->all();
        $have = array_fill_keys($existing, true);

        foreach (PlayType::query()->orderBy('sort_order')->orderBy('play_code')->cursor() as $pt) {
            if (isset($have[$pt->play_code])) {
                continue;
            }

            PlayConfigItem::query()->create([
                'version_id' => $vid,
                'play_code' => $pt->play_code,
                'category' => $pt->category,
                'dimension' => $pt->dimension,
                'bet_mode' => $pt->bet_mode,
                'display_name' => $pt->display_name,
                'is_enabled' => (bool) $pt->is_enabled,
                'min_bet_amount' => self::MIN_BET,
                'max_bet_amount' => self::MAX_BET,
                'display_order' => (int) $pt->sort_order,
                'supports_multi_number' => (bool) $pt->supports_multi_number,
                'reserved_rule_json' => $pt->reserved_rule_json,
                'rule_text_zh' => null,
                'rule_text_en' => null,
                'rule_text_ne' => null,
                'extra_config_json' => null,
            ]);
        }
    }

    private function syncOddsItemsForAllPlayTypes(OddsVersion $version): void
    {
        $vid = (int) $version->id;

        $currencies = OddsItem::query()
            ->where('version_id', $vid)
            ->distinct()
            ->pluck('currency_code')
            ->filter(static fn ($c) => is_string($c) && $c !== '')
            ->values();

        if ($currencies->isEmpty()) {
            $fallback = Currency::query()
                ->where('is_bettable', true)
                ->where('is_enabled', true)
                ->orderBy('code')
                ->value('code');
            if ($fallback === null || $fallback === '') {
                return;
            }
            $currencies = collect([strtoupper((string) $fallback)]);
        }

        foreach ($currencies as $currencyCode) {
            $currencyCode = strtoupper((string) $currencyCode);

            foreach (PlayType::query()->orderBy('sort_order')->orderBy('play_code')->cursor() as $pt) {
                $playCode = $pt->play_code;

                $anchor = OddsItem::query()
                    ->where('version_id', $vid)
                    ->where('play_code', $playCode)
                    ->where('currency_code', $currencyCode)
                    ->orderByDesc('id')
                    ->first();

                $rebate = (float) ($anchor?->rebate_rate ?? 0);
                $commission = (float) ($anchor?->commission_rate ?? 0);

                foreach (OddsStandardScopes::PRESET_ODDS_BY_SCOPE as $scope => $oddsValue) {
                    $exists = OddsItem::query()
                        ->where('version_id', $vid)
                        ->where('play_code', $playCode)
                        ->where('currency_code', $currencyCode)
                        ->where('prize_scope', $scope)
                        ->exists();
                    if ($exists) {
                        continue;
                    }

                    OddsItem::query()->create([
                        'version_id' => $vid,
                        'play_code' => $playCode,
                        'prize_scope' => $scope,
                        'odds_value' => $oddsValue,
                        'rebate_rate' => $rebate,
                        'commission_rate' => $commission,
                        'currency_code' => $currencyCode,
                        'extra_config_json' => null,
                    ]);
                }
            }
        }
    }
}
