<?php

namespace App\Support;

use App\Models\AgentNode;
use App\Models\AgentProfile;

/**
 * 将「平台 agent 角色」权限与线路内 {@see AgentProfile} 能力开关联动。
 *
 * 主账号绑定 slug=agent，不再按节点维护 agent_owner_*；创建玩家/下级 的开关须在登录态生效。
 */
final class AgentProfileCapabilityFilter
{
    /** @var list<string> */
    private const CHILD_AGENT_PERMISSION_CODES = [
        'agent.node.manage',
        'agent.profile.manage',
    ];

    /** @var list<string> */
    private const PLAYER_PERMISSION_CODES = [
        'service.players.manage',
        'service.players.freeze',
    ];

    /** @var list<string> */
    private const CHILD_AGENT_LEGACY_SLUGS = [
        'prd.agent.manage',
        'prd.agent.profile.manage',
    ];

    /** @var list<string> */
    private const PLAYER_LEGACY_SLUGS = [
        'prd.users.manage',
        'prd.users.view_cs',
        'prd.player_freeze.manage',
    ];

    private const SETTLEMENT_AGENT_MANAGE_CODE = 'settlement.agent.manage';

    /** 绑定代理主账号均可登记/确认与本节点直属边相关的账单（玩家↔直属代理、代理↔直接上下级）。 */
    public static function qualifiesForSettlementAgentManage(?AgentNode $node): bool
    {
        return $node !== null;
    }

    /**
     * 按 Profile 能力收紧或补足登录态 permission_code（平台 agent 角色模板未必含 manage）。
     *
     * @param  list<string>  $permissionCodes
     * @return list<string>
     */
    public static function applyToMenuActionCodes(
        array $permissionCodes,
        ?AgentProfile $profile,
        ?AgentNode $node = null,
    ): array
    {
        $set = [];
        foreach ($permissionCodes as $code) {
            if (is_string($code) && $code !== '') {
                $set[$code] = true;
            }
        }

        if (! ($profile?->can_create_child_agent ?? false)) {
            foreach (self::CHILD_AGENT_PERMISSION_CODES as $code) {
                unset($set[$code]);
            }
        } else {
            foreach (self::CHILD_AGENT_PERMISSION_CODES as $code) {
                $set[$code] = true;
            }
        }

        if (! ($profile?->can_create_player ?? false)) {
            foreach (self::PLAYER_PERMISSION_CODES as $code) {
                unset($set[$code]);
            }
        } else {
            foreach (self::PLAYER_PERMISSION_CODES as $code) {
                $set[$code] = true;
            }
        }

        if (self::qualifiesForSettlementAgentManage($node)) {
            $set[self::SETTLEMENT_AGENT_MANAGE_CODE] = true;
        }

        $out = array_keys($set);
        sort($out);

        return $out;
    }

    /**
     * @param  list<string>  $permissionCodes
     * @return list<string>
     */
    public static function filterMenuActionCodes(
        array $permissionCodes,
        ?AgentProfile $profile,
        ?AgentNode $node = null,
    ): array {
        return self::applyToMenuActionCodes($permissionCodes, $profile, $node);
    }

    /**
     * @param  list<string>  $legacySlugs
     * @return list<string>
     */
    public static function filterLegacySlugs(array $legacySlugs, ?AgentProfile $profile): array
    {
        $deny = [];
        if (! ($profile?->can_create_child_agent ?? false)) {
            $deny = array_merge($deny, self::CHILD_AGENT_LEGACY_SLUGS);
        }
        if (! ($profile?->can_create_player ?? false)) {
            $deny = array_merge($deny, self::PLAYER_LEGACY_SLUGS);
        }

        if ($deny === []) {
            return $legacySlugs;
        }

        $denySet = array_fill_keys($deny, true);

        return array_values(array_filter(
            $legacySlugs,
            static fn (string $slug): bool => ! isset($denySet[$slug]),
        ));
    }
}
