<?php

namespace App\Support;

use App\Models\AdminSite;
use App\Models\AdminUser;
use App\Models\Player;
use App\Lottery\ErrorCode;
use App\Support\ApiMessage;
use App\Support\ApiResponse;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;

/**
 * 后台站点数据范围：非超管仅可访问 {@see AdminUser::accessibleAdminSiteIds()} 绑定站点。
 *
 * 对应产品「site_only / site_all_data」；运行时以 admin_user_site_roles 为准（非已废弃的 admin_data_scopes 表）。
 */
final class AdminSiteScope
{
    /**
     * @return list<string>|null `null` 表示不限制（超管）
     */
    public static function accessibleSiteCodes(AdminUser $admin): ?array
    {
        $siteIds = $admin->accessibleAdminSiteIds();
        if ($siteIds === null) {
            return null;
        }

        if ($siteIds === []) {
            return [];
        }

        return AdminSite::query()
            ->whereIn('id', $siteIds)
            ->orderBy('code')
            ->pluck('code')
            ->map(static fn ($code): string => (string) $code)
            ->values()
            ->all();
    }

    public static function siteCodeAllowed(AdminUser $admin, string $siteCode): bool
    {
        $allowed = self::accessibleSiteCodes($admin);
        if ($allowed === null) {
            return true;
        }

        return in_array($siteCode, $allowed, true);
    }

    public static function siteIdAllowed(AdminUser $admin, int $siteId): bool
    {
        $siteIds = $admin->accessibleAdminSiteIds();
        if ($siteIds === null) {
            return true;
        }

        return in_array($siteId, $siteIds, true);
    }

    public static function playerAccessible(AdminUser $admin, Player $player): bool
    {
        if (! self::siteCodeAllowed($admin, (string) $player->site_code)) {
            return false;
        }

        return AdminAgentScope::playerAccessible($admin, $player);
    }

    /**
     * @param  Builder<Player>  $query
     */
    public static function applyToPlayerQuery(Builder $query, AdminUser $admin): void
    {
        $codes = self::accessibleSiteCodes($admin);
        if ($codes === null) {
            // Super admin - no site filtering
            AdminAgentScope::applyToPlayerQuery($query, $admin);

            return;
        }

        if ($codes === []) {
            $query->whereRaw('0 = 1');

            return;
        }

        $query->whereIn('site_code', $codes);

        AdminAgentScope::applyToPlayerQuery($query, $admin);
    }

    /**
     * 在站点范围基础上，可选按请求的 site_code 再收窄。
     *
     * @param  Builder<Player>  $query
     */
    public static function applyPlayerFilters(
        Builder $query,
        AdminUser $admin,
        ?string $requestedSiteCode,
        ?int $requestedAgentNodeId = null,
    ): void {
        self::applyToPlayerQuery($query, $admin);

        $siteCode = is_string($requestedSiteCode) ? trim($requestedSiteCode) : '';
        if ($siteCode !== '') {
            if (! self::siteCodeAllowed($admin, $siteCode)) {
                $query->whereRaw('0 = 1');

                return;
            }

            $query->where('site_code', $siteCode);
        }

        if ($requestedAgentNodeId !== null && $requestedAgentNodeId > 0) {
            AdminAgentScope::applyRequestedAgentNodeFilter($query, $admin, $requestedAgentNodeId);
        }
    }

    /**
     * @param  Builder<mixed>  $query
     */
    public static function applyViaPlayerRelation(Builder $query, AdminUser $admin, string $relation = 'player'): void
    {
        if ($admin->isSuperAdmin()) {
            return;
        }

        $query->whereHas($relation, static function (Builder $playerQuery) use ($admin): void {
            self::applyToPlayerQuery($playerQuery, $admin);
        });
    }

    /**
     * @param  Builder<mixed>  $query
     */
    public static function applyViaPlayerRelationWithSiteCode(
        Builder $query,
        AdminUser $admin,
        ?string $requestedSiteCode,
        string $relation = 'player',
        ?int $requestedAgentNodeId = null,
    ): void {
        if ($admin->isSuperAdmin()) {
            $siteCode = is_string($requestedSiteCode) ? trim($requestedSiteCode) : '';
            $agentNodeId = $requestedAgentNodeId !== null && $requestedAgentNodeId > 0
                ? $requestedAgentNodeId
                : null;

            if ($siteCode === '' && $agentNodeId === null) {
                return;
            }

            $query->whereHas($relation, static function (Builder $playerQuery) use ($admin, $siteCode, $agentNodeId): void {
                self::applyPlayerFilters($playerQuery, $admin, $siteCode !== '' ? $siteCode : null, $agentNodeId);
            });

            return;
        }

        $query->whereHas($relation, static function (Builder $playerQuery) use ($admin, $requestedSiteCode, $requestedAgentNodeId): void {
            self::applyPlayerFilters($playerQuery, $admin, $requestedSiteCode, $requestedAgentNodeId);
        });
    }

    public static function denyUnlessPlayerAccessible(AdminUser $admin, Player $player): ?JsonResponse
    {
        if (! self::playerAccessible($admin, $player)) {
            return ApiMessage::errorResponse(
                request(),
                'admin.site_player_access_denied',
                ErrorCode::AdminForbidden->value,
                null,
                403,
            );
        }

        return null;
    }
}
