<?php

namespace App\Services\Integration;

use App\Models\AdminSite;
use App\Models\Player;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;

/**
 * 按 {@see site_code} 解析主站对接配置；未命中库表时回退全局 MAIN_SITE_* env（并写 warning 日志）。
 */
final class PartnerSiteConfigResolver
{
    private const CACHE_PREFIX = 'partner_site_config:';

    private const CACHE_TTL_SECONDS = 60;

    public function resolveForPlayer(Player $player): PartnerSiteConfig
    {
        return $this->resolveBySiteCode((string) $player->site_code);
    }

    public function resolveBySiteCode(string $siteCode): PartnerSiteConfig
    {
        $siteCode = trim($siteCode);
        if ($siteCode === '') {
            return $this->legacyFallbackConfig($siteCode);
        }

        $cacheKey = self::CACHE_PREFIX.$siteCode;

        /** @var array<string, mixed> $cached */
        $cached = Cache::remember($cacheKey, self::CACHE_TTL_SECONDS, function () use ($siteCode): array {
            $site = AdminSite::query()->where('code', $siteCode)->first();
            $config = $site !== null
                ? $this->fromAdminSite($site)
                : $this->legacyFallbackConfig($siteCode);

            return $config->toCacheArray();
        });

        return PartnerSiteConfig::fromCacheArray($cached);
    }

    public function forgetCache(string $siteCode): void
    {
        Cache::forget(self::CACHE_PREFIX.trim($siteCode));
    }

    /**
     * 从未验签的 JWT 中读取 site_code（仅用于选取验签密钥）。
     */
    public function peekSiteCodeFromJwt(string $jwt): ?string
    {
        $jwt = trim($jwt);
        $parts = explode('.', $jwt);
        if (count($parts) !== 3) {
            return null;
        }

        $payloadJson = $this->base64UrlDecode($parts[1]);
        if ($payloadJson === null) {
            return null;
        }

        $payload = json_decode($payloadJson, true);
        if (! is_array($payload)) {
            return null;
        }

        $siteKey = (string) config('lottery.player_auth.jwt.claim_site_code', 'site_code');
        $siteCode = $payload[$siteKey] ?? null;

        return is_string($siteCode) && $siteCode !== '' ? $siteCode : null;
    }

    private function fromAdminSite(AdminSite $site): PartnerSiteConfig
    {
        return new PartnerSiteConfig(
            siteCode: (string) $site->code,
            enabled: $site->isEnabled(),
            walletApiUrl: is_string($site->wallet_api_url) && $site->wallet_api_url !== ''
                ? rtrim($site->wallet_api_url, '/')
                : null,
            walletDebitPath: (string) ($site->wallet_debit_path ?: '/wallet/debit-for-lottery'),
            walletCreditPath: (string) ($site->wallet_credit_path ?: '/wallet/credit-from-lottery'),
            walletBalancePath: (string) ($site->wallet_balance_path ?: '/wallet/balance'),
            walletLookupIdempotentPath: (string) config('lottery.main_site.wallet_lookup_idempotent_path', '/wallet/lookup-idempotent'),
            ssoJwtSecret: $site->decryptedSsoJwtSecret(),
            walletApiKey: $site->decryptedWalletApiKey(),
            walletTimeoutSeconds: max(1, (int) ($site->wallet_timeout_seconds ?? 10)),
            source: PartnerSiteConfig::SOURCE_DATABASE,
        );
    }

    private function legacyFallbackConfig(string $siteCode): PartnerSiteConfig
    {
        $defaultCode = (string) config('lottery.integration.default_site_code', 'default_site');
        $legacyCodes = array_filter([
            $defaultCode,
            (string) config('lottery.integration.legacy_env_site_code', ''),
        ]);

        $sso = config('lottery.main_site.sso_jwt_secret');
        $walletUrl = config('lottery.main_site.wallet_api_url');
        $walletKey = config('lottery.main_site.wallet_api_key');

        $hasLegacy = (is_string($sso) && $sso !== '')
            || (is_string($walletUrl) && trim((string) $walletUrl) !== '');

        if ($hasLegacy && (
            $siteCode === ''
            || in_array($siteCode, $legacyCodes, true)
            || app()->environment(['local', 'testing'])
        )) {
            if ($siteCode !== '') {
                Log::warning('partner_site_config.legacy_env_fallback', [
                    'site_code' => $siteCode,
                    'hint' => 'Configure admin_sites row for this site_code',
                ]);
            }

            return new PartnerSiteConfig(
                siteCode: $siteCode !== '' ? $siteCode : $defaultCode,
                enabled: true,
                walletApiUrl: is_string($walletUrl) && trim($walletUrl) !== ''
                    ? rtrim(trim($walletUrl), '/')
                    : null,
                walletDebitPath: (string) config('lottery.main_site.wallet_debit_path', '/wallet/debit-for-lottery'),
                walletCreditPath: (string) config('lottery.main_site.wallet_credit_path', '/wallet/credit-from-lottery'),
                walletBalancePath: (string) config('lottery.main_site.wallet_balance_path', '/wallet/balance'),
                walletLookupIdempotentPath: (string) config('lottery.main_site.wallet_lookup_idempotent_path', '/wallet/lookup-idempotent'),
                ssoJwtSecret: is_string($sso) && $sso !== '' ? $sso : null,
                walletApiKey: is_string($walletKey) && $walletKey !== '' ? $walletKey : null,
                walletTimeoutSeconds: max(1, (int) config('lottery.main_site.wallet_timeout', 10)),
                source: PartnerSiteConfig::SOURCE_LEGACY_ENV,
            );
        }

        return new PartnerSiteConfig(
            siteCode: $siteCode,
            enabled: false,
            walletApiUrl: null,
            walletDebitPath: '/wallet/debit-for-lottery',
            walletCreditPath: '/wallet/credit-from-lottery',
            walletBalancePath: '/wallet/balance',
            walletLookupIdempotentPath: '/wallet/lookup-idempotent',
            ssoJwtSecret: null,
            walletApiKey: null,
            walletTimeoutSeconds: 10,
            source: PartnerSiteConfig::SOURCE_DATABASE,
        );
    }

    private function base64UrlDecode(string $segment): ?string
    {
        $remainder = strlen($segment) % 4;
        if ($remainder > 0) {
            $segment .= str_repeat('=', 4 - $remainder);
        }

        $decoded = base64_decode(strtr($segment, '-_', '+/'), true);

        return $decoded === false ? null : $decoded;
    }
}
