<?php

namespace App\Support;

use App\Models\AdminUser;
use App\Models\AgentNode;
use Illuminate\Database\Query\Builder;

/**
 * 站点 + 代理子树：用于报表等 Query Builder（players 表别名）。
 */
final class AdminDataScope
{
    /**
     * @param  Builder<mixed>  $query  已 join `players as {alias}`
     */
    public static function applyToPlayersAlias(
        Builder $query,
        ?AdminUser $admin,
        string $alias = 'p',
        ?int $requestedAgentNodeId = null,
    ): void {
        if ($admin === null) {
            return;
        }

        if ($admin->isSuperAdmin()) {
            if ($requestedAgentNodeId !== null && $requestedAgentNodeId > 0) {
                self::applyAgentNodeIdOnAlias($query, $admin, $alias, $requestedAgentNodeId);
            }

            return;
        }

        $codes = AdminSiteScope::accessibleSiteCodes($admin);
        if ($codes !== null) {
            if ($codes === []) {
                $query->whereRaw('0 = 1');

                return;
            }

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

        $actor = AdminAgentScope::primaryAgentNode($admin);
        if ($actor === null) {
            if (! AdminAgentScope::isSiteOnlyOperator($admin)) {
                $query->whereRaw('0 = 1');
            } elseif ($requestedAgentNodeId !== null && $requestedAgentNodeId > 0) {
                self::applyAgentNodeIdOnAlias($query, $admin, $alias, $requestedAgentNodeId);
            }

            return;
        }

        if (! \Illuminate\Support\Facades\Schema::hasColumn('players', 'agent_node_id')) {
            return;
        }

        $subtreeIds = AgentNode::query()
            ->where('path', 'like', $actor->path.'%')
            ->pluck('id')
            ->all();

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

            return;
        }

        $query->whereIn($alias.'.agent_node_id', $subtreeIds);

        if ($requestedAgentNodeId !== null && $requestedAgentNodeId > 0) {
            self::applyAgentNodeIdOnAlias($query, $admin, $alias, $requestedAgentNodeId);
        }
    }

    /**
     * @param  Builder<mixed>  $query
     */
    private static function applyAgentNodeIdOnAlias(
        Builder $query,
        AdminUser $admin,
        string $alias,
        int $agentNodeId,
    ): void {
        $node = AgentNode::query()->find($agentNodeId);
        if ($node === null || ! AdminAgentScope::nodeVisibleTo($admin, $node)) {
            $query->whereRaw('0 = 1');

            return;
        }

        $subtreeIds = AgentNode::query()
            ->where('path', 'like', $node->path.'%')
            ->pluck('id')
            ->all();

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

            return;
        }

        $query->whereIn($alias.'.agent_node_id', $subtreeIds);
    }

    /**
     * Eloquent 模型经 player 关联做站点 + 代理子树过滤。
     *
     * @param  \Illuminate\Database\Eloquent\Builder<mixed>  $query
     */
    public static function applyEloquentViaPlayer(
        \Illuminate\Database\Eloquent\Builder $query,
        AdminUser $admin,
        string $relation = 'player',
    ): void {
        if ($admin->isSuperAdmin()) {
            return;
        }

        $query->whereHas($relation, static function (\Illuminate\Database\Eloquent\Builder $playerQuery) use ($admin): void {
            AdminSiteScope::applyToPlayerQuery($playerQuery, $admin);
        });
    }

    /**
     * 约束 ticket_orders（别名 o）仅统计可见玩家。
     *
     * @param  Builder<mixed>  $query
     */
    public static function applyToTicketOrdersViaPlayer(Builder $query, ?AdminUser $admin, string $orderAlias = 'o'): void
    {
        if ($admin === null || $admin->isSuperAdmin()) {
            return;
        }

        $query->whereExists(function (Builder $sub) use ($admin, $orderAlias): void {
            $sub->from('players as scope_p')
                ->whereColumn('scope_p.id', $orderAlias.'.player_id');
            self::applyToPlayersAlias($sub, $admin, 'scope_p');
        });
    }
}
