import logging
import time
from typing import Callable
from fastapi import Request, Response 
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware
from .config import settings
from .database import CoreSessionLocal
from .security import get_tenant_from_token, verify_token

logger = logging.getLogger(__name__)

class TenantMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next: Callable):
        # Rutas públicas que no requieren tenant
        # Permitir acceso sin autenticación a rutas de documentación y salud
        doc_prefixes = ["/api/redoc", "/api/openapi.json"]
        public_prefixes = [
            "/api/v1/auth",
            "/api/v1/status",
            "/api/health",
            "/api/",
            "/uploads",
        ]

        path = request.url.path

        # 3. Bypass para rutas públicas y docs
        if any(path == prefix or path.startswith(prefix + "/") for prefix in doc_prefixes):
            return await call_next(request)
            
        if any(path == prefix or (prefix != "/" and path.startswith(prefix)) for prefix in public_prefixes):
            return await call_next(request)

        # 4. Validación estricta de Token (solo para lo que no es público ni OPTIONS)
        auth_header = request.headers.get("Authorization")
        if not auth_header or not auth_header.startswith("Bearer "):
            return JSONResponse(
                status_code=401,
                content={
                    "error": "HTTP_ERROR",
                    "message": "Missing or invalid authorization header",
                    "status_code": 401,
                }
            )

        token = auth_header.split(" ")[1]
        try:
            user_info = verify_token(token)
            tenant_id = get_tenant_from_token(user_info)
            
            request.state.tenant_id = tenant_id
            request.state.user_info = user_info
        except Exception as e:
            logger.error(f"❌ Tenant validation error: {str(e)}")
            return JSONResponse(
                status_code=401,
                content={
                    "error": "HTTP_ERROR",
                    "message": "Invalid authentication",
                    "status_code": 401,
                }
            )

        # 5. Continuar con la petición real
        return await call_next(request)


class LicenseValidationMiddleware(BaseHTTPMiddleware):
    """
    Middleware para validar la licencia del tenant antes de procesar requests
    """

    async def dispatch(self, request: Request, call_next: Callable):
        if not settings.LICENSE_CHECK_ENABLED:
            return await call_next(request)

        # Rutas que no requieren validación de licencia
        exempt_paths = [
            "/api/docs",
            "/api/redoc",
            "/openapi.json",
            "/api/v1/auth",
            "/api/v1/auth",
            "/api/v1/status",
            "/api/v1/status",
            "/api/health",
            "/api/",
        ]

        # Verificar si la ruta está exenta (comparación exacta o prefijo)
        is_exempt = False
        for path in exempt_paths:
            if request.url.path == path or (
                path != "/" and request.url.path.startswith(path)
            ):
                is_exempt = True
                break

        if is_exempt:
            return await call_next(request)

        # Obtener tenant_id del request state (debe ser seteado por TenantMiddleware)
        tenant_id = getattr(request.state, "tenant_id", None)

        if not tenant_id:
            return await call_next(request)  # Dejamos que TenantMiddleware maneje esto

        # Validar licencia
        db = CoreSessionLocal()
        try:
            # Importar aquí para evitar imports circulares
            from api.v1.modules.core.licenses.service import LicenseService

            license_service = LicenseService(db)
            license_info = license_service.validate_license(tenant_id)

            if not license_info["is_valid"]:
                return JSONResponse(
                    status_code=402,
                    content={
                        "error": "HTTP_ERROR",
                        "message": f"License validation failed: {license_info['reason']}",
                        "status_code": 402,
                    }
                )

            # Agregar info de licencia al request state
            request.state.license_info = license_info

        except Exception as e:
            logger.error(f"License validation error: {str(e)}")
            return JSONResponse(
                status_code=500,
                content={
                    "error": "HTTP_ERROR",
                    "message": "License validation error",
                    "status_code": 500,
                }
            )
        finally:
            db.close()

        response = await call_next(request)
        return response


class RequestLoggingMiddleware(BaseHTTPMiddleware):
    """
    Middleware para logging de requests
    """

    async def dispatch(self, request: Request, call_next: Callable):
        start_time = time.time()

        excluded_paths = [
            "/api/docs",
            "/api/redoc",
            "/openapi.json",
            "/api/v1/status",
            "/api/health",
        ]
        if any(
            request.url.path == path or request.url.path.startswith(path + "/")
            for path in excluded_paths
        ):
            return await call_next(request)

        # Log request
        logger.info(f"Request: {request.method} {request.url.path}")

        response = await call_next(request)

        # Log response
        process_time = time.time() - start_time
        logger.info(
            f"Response: {request.method} {request.url.path} "
            f"Status: {response.status_code} "
            f"Duration: {process_time:.3f}s"
        )

        # Agregar header con tiempo de procesamiento
        response.headers["X-Process-Time"] = str(process_time)

        return response
