<?php

namespace App\Services\Player;

use Throwable;
use App\Models\AdminSite;
use App\Lottery\ErrorCode;
use Illuminate\Support\Facades\Schema;
use App\Exceptions\PlayerAuthenticationException;

final class NativeJwtSecretGuard
{
    public function validatedSecret(): string
    {
        $secret = config('lottery.player_auth.native.secret');
        if (! is_string($secret) || $secret === '') {
            $this->rejectConfiguration('原生登录未配置');
        }

        $legacySsoSecret = config('lottery.main_site.sso_jwt_secret');
        if ($this->matches($secret, $legacySsoSecret)) {
            $this->rejectConfiguration('原生登录密钥不得与 legacy SSO 密钥相同');
        }

        if ($this->matchesStoredSiteSsoSecret($secret)) {
            $this->rejectConfiguration('原生登录密钥不得与任何站点保存的 SSO 密钥相同');
        }

        return $secret;
    }

    private function matchesStoredSiteSsoSecret(string $nativeSecret): bool
    {
        try {
            if (! Schema::hasTable('admin_sites')
                || ! Schema::hasColumn('admin_sites', 'sso_jwt_secret_encrypted')) {
                return false;
            }

            $sites = AdminSite::query()
                ->whereNotNull('sso_jwt_secret_encrypted')
                ->get(['sso_jwt_secret_encrypted']);
        } catch (Throwable) {
            $this->rejectConfiguration('无法检查原生登录密钥是否与站点 SSO 密钥冲突');
        }

        foreach ($sites as $site) {
            if ($this->matches($nativeSecret, $site->decryptedSsoJwtSecret())) {
                return true;
            }
        }

        return false;
    }

    private function matches(string $nativeSecret, mixed $candidate): bool
    {
        return is_string($candidate)
            && $candidate !== ''
            && hash_equals($nativeSecret, $candidate);
    }

    private function rejectConfiguration(string $message): never
    {
        throw new PlayerAuthenticationException(
            $message,
            ErrorCode::PlayerSsoSecretNotConfigured->value,
            503,
        );
    }
}
