"""
Dependencias de FastAPI para verificación de permisos multi-tenant.
Proporciona decoradores y funciones para proteger rutas con permisos específicos.
"""

from typing import List, Optional, Callable
from fastapi import Depends, HTTPException, status, Header
from sqlalchemy.orm import Session
from functools import wraps
from core.database import get_core_db
from core.security import get_current_user  # Asumiendo que existe esta función
from .service import PermissionService

# Dependencia para obtener el servicio de permisos
def get_permission_service(db: Session = Depends(get_core_db)) -> PermissionService:
    """
    Crea una instancia del servicio de permisos con la sesión de base de datos.
    """
    return PermissionService(db)


# Clase para verificación de permisos (puede usarse como dependencia)
class PermissionChecker:
    """
    Verificador de permisos que puede usarse como dependencia de FastAPI.

    Ejemplo de uso:
        @app.get("/invoices")
        async def list_invoices(
            _: None = Depends(PermissionChecker(["invoice.view"]))
        ):
            return {"invoices": [...]}
    """

    def __init__(self, required_permissions: List[str], require_all: bool = True):
        """
        Args:
            required_permissions: Lista de permisos requeridos
            require_all: Si True, requiere TODOS los permisos.
                        Si False, requiere AL MENOS UNO.
        """
        self.required_permissions = required_permissions
        self.require_all = require_all

    async def __call__(
        self,
        client_id: int,
        current_user: dict = Depends(get_current_user),        
        permission_service: PermissionService = Depends(get_permission_service),        
    ):
        """
        Verifica que el usuario tenga los permisos requeridos.

        Lanza HTTPException 403 si no tiene permisos.
        """
        user_id = current_user.get("sub") or current_user.get("id")

        if not user_id:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="User ID not found in token",
            )

        # Verificar permisos
        if self.require_all:
            has_access = permission_service.has_all_permissions(
                user_id=user_id,
                client_id=client_id,
                permission_codes=self.required_permissions,
            )
        else:
            has_access = permission_service.has_any_permission(
                user_id=user_id,
                client_id=client_id,
                permission_codes=self.required_permissions,
            )

        if not has_access:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail=f"Missing required permissions: {', '.join(self.required_permissions)}",
            )

        return True


# Función alternativa para verificar un solo permiso
class RequirePermission:
    """
    Verificador simple para un único permiso.

    Ejemplo:
        @app.post("/invoices")
        async def create_invoice(
            _: None = Depends(RequirePermission("invoice.create"))
        ):
            return {"created": True}
    """

    def __init__(self, permission_code: str):
        self.permission_code = permission_code

    async def __call__(
        self,
        client_id: int,
        current_user: dict = Depends(get_current_user),        
        permission_service: PermissionService = Depends(get_permission_service),
    ):
        user_id = current_user.get("sub") or current_user.get("id")

        if not user_id:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="User ID not found in token",
            )

        has_permission = permission_service.has_permission(
            user_id=user_id, client_id=client_id, permission_code=self.permission_code
        )

        if not has_permission:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail=f"Missing required permission: {self.permission_code}",
            )

        return True


# Decorador personalizado para aplicar a funciones (opcional)
def require_permissions(*permissions: str, require_all: bool = True):
    """
    Decorador para verificar permisos en funciones.
    Útil para lógica de negocio fuera de rutas FastAPI.

    Ejemplo:
        @require_permissions("invoice.edit", "invoice.view")
        def update_invoice_logic(invoice_id: int, user_id: str, client_id: int, db: Session):
            # Lógica de actualización
            pass
    """

    def decorator(func: Callable):
        @wraps(func)
        def wrapper(*args, **kwargs):
            # Extraer user_id, client_id y db de los argumentos
            user_id = kwargs.get("user_id")
            client_id = kwargs.get("client_id")
            db = kwargs.get("db")

            if not all([user_id, client_id, db]):
                raise ValueError(
                    "Function must receive 'user_id', 'client_id', and 'db' as keyword arguments"
                )

            # Verificar permisos
            permission_service = PermissionService(db)

            if require_all:
                has_access = permission_service.has_all_permissions(
                    user_id=user_id,
                    client_id=client_id,
                    permission_codes=list(permissions),
                )
            else:
                has_access = permission_service.has_any_permission(
                    user_id=user_id,
                    client_id=client_id,
                    permission_codes=list(permissions),
                )

            if not has_access:
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail=f"Missing required permissions: {', '.join(permissions)}",
                )

            return func(*args, **kwargs)

        return wrapper

    return decorator


# Función helper para obtener permisos del usuario actual
async def get_current_user_permissions(
    client_id: int,
    current_user: dict = Depends(get_current_user),    
    permission_service: PermissionService = Depends(get_permission_service),
) -> set:
    """
    Devuelve todos los permisos del usuario actual en el cliente.
    Útil para endpoints que necesitan conocer los permisos disponibles.
    """
    user_id = current_user.get("sub") or current_user.get("id")

    if not user_id:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="User ID not found in token",
        )

    return permission_service.get_user_permissions(user_id, client_id)
