'use client';

import React from 'react';
import { Spin } from 'antd';
import { usePermissions } from '@/contexts/PermissionsContext';
import { PermissionDeniedNotice } from '@/components/permissions/PermissionDeniedNotice';

interface PermissionGuardProps {
    children: React.ReactNode;
    permission?: string;
    role?: string;
    roles?: string[];
    permissions?: string[];
    module?: string;
    action?: string;
    fallback?: React.ReactNode;
    show?: boolean;
    /**
     * Na página: se não houver `fallback`, mostra aviso com a permissão em falta.
     * No menu continue a omitir o item (notice omitido).
     */
    notice?: boolean;
    deniedAction?: string;
    /**
     * UI enquanto permissões carregam. Por omissão: spinner (gates de página) ou
     * `null` (botões/CTAs sem `fallback`/`notice`, para não flashar "sem permissão").
     */
    loadingFallback?: React.ReactNode;
}

function DefaultPermissionsLoading() {
    return (
        <div
            style={{ padding: 48, textAlign: 'center' }}
            aria-busy="true"
            aria-live="polite"
            data-testid="permission-guard-loading"
        >
            <Spin size="large" />
        </div>
    );
}

export function PermissionGuard({
    children,
    permission,
    role,
    roles,
    permissions,
    module,
    action,
    fallback = null,
    show = true,
    notice = false,
    deniedAction,
    loadingFallback,
}: PermissionGuardProps) {
    const {
        hasPermission,
        hasRole,
        hasAnyRole,
        hasAnyPermission,
        canAccess,
        loading,
    } = usePermissions();

    // Nunca decidir "sem permissão" enquanto grants ainda carregam (flash 403 → conteúdo).
    if (loading) {
        if (loadingFallback !== undefined) {
            return <>{loadingFallback}</>;
        }
        // Gate de página (fallback/notice): spinner. CTA/menu: omitir até estar pronto.
        if (fallback != null || notice) {
            return <DefaultPermissionsLoading />;
        }
        return null;
    }

    let hasAccess = true;

    if (permission) {
        hasAccess = hasAccess && hasPermission(permission);
    }

    if (role) {
        hasAccess = hasAccess && hasRole(role);
    }

    if (roles && roles.length > 0) {
        hasAccess = hasAccess && hasAnyRole(roles);
    }

    if (permissions && permissions.length > 0) {
        hasAccess = hasAccess && hasAnyPermission(permissions);
    }

    if (module && action) {
        hasAccess = hasAccess && canAccess(module, action);
    }

    if (!hasAccess) {
        if (!show) {
            return null;
        }
        if (fallback != null) {
            return <>{fallback}</>;
        }
        if (notice) {
            return <PermissionDeniedNotice permission={permission} action={deniedAction} />;
        }
        return null;
    }

    return <>{children}</>;
}
