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

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

logger = logging.getLogger(__name__)


# 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)


def _authorize(
    permission_service: PermissionService,
    user_id: str,
    company_id: int,
    codes: List[str],
    require_all: bool,
) -> bool:
    """Verifica permisos y, en desarrollo, aplica auto-bootstrap si el acceso falla.

    Replica el bootstrap perezoso de ``core.security.validate_access_to_resource``:
    en ``development`` el usuario (incluido el dev local) obtiene el rol super_admin
    con todos los permisos la primera vez que lo necesita, para no bloquear el
    entorno de desarrollo al activar el enforcement de permisos por área/carril.
    """
    check = permission_service.has_all_permissions if require_all else permission_service.has_any_permission
    if check(user_id=user_id, company_id=company_id, permission_codes=codes):
        return True
    if settings.ENVIRONMENT == "development":
        try:
            permission_service.bootstrap_super_admin(user_id, company_id)
            if check(user_id=user_id, company_id=company_id, permission_codes=codes):
                logger.info("Auto-bootstrap de permisos en dev: user_id=%s company_id=%s", user_id, company_id)
                return True
        except Exception as exc:  # el bootstrap nunca debe escalar como acceso concedido
            logger.warning("Auto-bootstrap de permisos falló: %s", exc)
    return False


# 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,
        company_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 sobre la compañía (con auto-bootstrap en desarrollo)
        if not _authorize(permission_service, user_id, company_id, self.required_permissions, self.require_all):
            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,
        company_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",
            )

        if not _authorize(permission_service, user_id, company_id, [self.permission_code], require_all=True):
            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, company_id: int, db: Session):
            # Lógica de actualización
            pass
    """

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

            if not all([user_id, company_id, db]):
                raise ValueError(
                    "Function must receive 'user_id', 'company_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,
                    company_id=company_id,
                    permission_codes=list(permissions),
                )
            else:
                has_access = permission_service.has_any_permission(
                    user_id=user_id,
                    company_id=company_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(
    company_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 la compañía.
    Ú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, company_id, use_cache=True)
