<?php

namespace App\Services\Currency;

use App\Models\Currency;
use App\Models\OddsItem;
use App\Models\PlayType;
use App\Models\JackpotPool;
use App\Models\OddsVersion;
use Illuminate\Support\Facades\DB;
use App\Support\OddsStandardScopes;

/**
 * 为新开通下注能力的币种补齐最小可运营数据。
 */
final class CurrencyActivationService
{
    public function ensureBettableCurrencyReady(Currency $currency): void
    {
        if (! $currency->is_enabled || ! $currency->is_bettable) {
            return;
        }

        DB::transaction(function () use ($currency): void {
            $currencyCode = strtoupper((string) $currency->code);

            $this->ensureJackpotPool($currencyCode);
            $this->ensureOddsItems($currencyCode);
        });
    }

    private function ensureJackpotPool(string $currencyCode): void
    {
        $exists = JackpotPool::query()
            ->where('currency_code', $currencyCode)
            ->exists();

        if ($exists) {
            return;
        }

        $source = JackpotPool::query()
            ->where('currency_code', '!=', $currencyCode)
            ->orderByDesc('status')
            ->orderBy('currency_code')
            ->first();

        JackpotPool::query()->create([
            'currency_code' => $currencyCode,
            'current_amount' => 0,
            'contribution_rate' => (string) ($source?->contribution_rate ?? '0.0200'),
            'trigger_threshold' => (int) ($source?->trigger_threshold ?? 100_000_000),
            'payout_rate' => (string) ($source?->payout_rate ?? '0.5000'),
            'force_trigger_draw_gap' => (int) ($source?->force_trigger_draw_gap ?? 100),
            'min_bet_amount' => (int) ($source?->min_bet_amount ?? 100),
            'combo_trigger_play_codes' => $source?->combo_trigger_play_codes,
            'status' => (int) ($source?->status ?? 0),
            'last_trigger_draw_id' => null,
        ]);
    }

    private function ensureOddsItems(string $currencyCode): void
    {
        OddsVersion::query()
            ->orderBy('id')
            ->each(function (OddsVersion $version) use ($currencyCode): void {
                $this->ensureOddsItemsForVersion($version, $currencyCode);
            });
    }

    private function ensureOddsItemsForVersion(OddsVersion $version, string $currencyCode): void
    {
        $hasTargetCurrency = OddsItem::query()
            ->where('version_id', $version->id)
            ->where('currency_code', $currencyCode)
            ->exists();

        if ($hasTargetCurrency) {
            OddsStandardScopes::syncMissingForVersion($version);

            return;
        }

        $sourceCurrency = OddsItem::query()
            ->where('version_id', $version->id)
            ->where('currency_code', '!=', $currencyCode)
            ->orderBy('currency_code')
            ->value('currency_code');

        if (is_string($sourceCurrency) && $sourceCurrency !== '') {
            OddsItem::query()
                ->where('version_id', $version->id)
                ->where('currency_code', $sourceCurrency)
                ->orderBy('play_code')
                ->orderBy('prize_scope')
                ->get()
                ->each(function (OddsItem $item) use ($version, $currencyCode): void {
                    OddsItem::query()->firstOrCreate(
                        [
                            'version_id' => $version->id,
                            'play_code' => $item->play_code,
                            'prize_scope' => $item->prize_scope,
                            'currency_code' => $currencyCode,
                        ],
                        [
                            'odds_value' => (int) $item->odds_value,
                            'rebate_rate' => (float) $item->rebate_rate,
                            'commission_rate' => (float) $item->commission_rate,
                            'extra_config_json' => $item->extra_config_json,
                        ],
                    );
                });

            OddsStandardScopes::syncMissingForVersion($version);

            return;
        }

        foreach (PlayType::query()->orderBy('sort_order')->orderBy('play_code')->get() as $playType) {
            foreach (OddsStandardScopes::PRESET_ODDS_BY_SCOPE as $scope => $oddsValue) {
                OddsItem::query()->firstOrCreate(
                    [
                        'version_id' => $version->id,
                        'play_code' => $playType->play_code,
                        'prize_scope' => $scope,
                        'currency_code' => $currencyCode,
                    ],
                    [
                        'odds_value' => $oddsValue,
                        'rebate_rate' => 0,
                        'commission_rate' => 0,
                        'extra_config_json' => null,
                    ],
                );
            }
        }
    }
}
