<?php

namespace App\Support;

use App\Models\AdminRole;
use App\Models\AdminUser;
use App\Models\AgentNode;
use Illuminate\Validation\ValidationException;

final class AgentRoleAuthorization
{
    public static function roleVisibleTo(AdminUser $admin, AdminRole $role): bool
    {
        if ($admin->isSuperAdmin()) {
            return true;
        }

        if ($role->scope_type !== AdminRole::SCOPE_AGENT || $role->owner_agent_id === null) {
            return false;
        }

        $owner = AgentNode::query()->find((int) $role->owner_agent_id);
        if ($owner === null) {
            return false;
        }

        return AdminAgentScope::nodeVisibleTo($admin, $owner);
    }

    public static function roleManageableBy(AdminUser $admin, AdminRole $role): bool
    {
        if ($role->delegated_from_role_id !== null) {
            return false;
        }

        if (! self::roleVisibleTo($admin, $role)) {
            return false;
        }

        return $admin->isSuperAdmin() || $admin->hasPermissionCode('agent.role.manage');
    }

    /**
     * @param  list<string>  $permissionSlugs
     */
    public static function assertSlugsWithinActor(AdminUser $actor, array $permissionSlugs): void
    {
        if ($actor->isSuperAdmin()) {
            return;
        }

        $allowed = $actor->adminPermissionSlugs();
        $invalid = array_values(array_diff($permissionSlugs, $allowed));
        if ($invalid !== []) {
            throw ValidationException::withMessages([
                'permission_slugs' => ['permission_exceeds_actor: '.implode(', ', $invalid)],
            ]);
        }
    }

    /**
     * @param  list<string>  $permissionSlugs
     */
    public static function assertSlugsForAgentRole(
        AdminUser $actor,
        AgentNode $ownerAgent,
        array $permissionSlugs,
    ): void {
        if ($actor->isSuperAdmin()) {
            return;
        }

        self::assertSlugsWithinActor($actor, $permissionSlugs);
        AgentDelegationAuthorization::assertRoleSlugsWithinAgentCeiling($ownerAgent, $permissionSlugs, $actor);
    }

    public static function denyUnlessRoleManageable(AdminUser $admin, AdminRole $role): ?\Illuminate\Http\JsonResponse
    {
        if (self::roleManageableBy($admin, $role)) {
            return null;
        }

        return ApiMessage::errorResponse(
            request(),
            'admin.agent_role_manage_denied',
            \App\Lottery\ErrorCode::AdminForbidden->value,
            null,
            403,
        );
    }
}
