"""
FastAPI Authentication Dependencies and Factory Functions.

Provides:
- get_keycloak_config_from_env(): Create config from env vars
- get_authenticator(): Create HybridAuthenticator instance
- get_auth(): Global authenticator singleton
- get_current_user(): FastAPI dependency for authentication
- require_role(): FastAPI dependency factory for role-based access
"""

import os
import logging
from typing import Optional, Dict, Any

from fastapi import Request, HTTPException, Depends

from .keycloak_auth import (
    KeycloakConfig,
    KeycloakConfigError,
    HybridAuthenticator,
    TokenExpiredError,
    TokenInvalidError,
)

logger = logging.getLogger(__name__)


# =============================================
# FACTORY FUNCTIONS
# =============================================

def get_keycloak_config_from_env() -> Optional[KeycloakConfig]:
    """
    Create KeycloakConfig from environment variables.

    Required env vars:
    - KEYCLOAK_SERVER_URL: e.g., https://keycloak.breakpilot.app
    - KEYCLOAK_REALM: e.g., breakpilot
    - KEYCLOAK_CLIENT_ID: e.g., breakpilot-backend

    Optional:
    - KEYCLOAK_CLIENT_SECRET: For confidential clients
    - KEYCLOAK_VERIFY_SSL: Default true
    """
    server_url = os.environ.get("KEYCLOAK_SERVER_URL")
    realm = os.environ.get("KEYCLOAK_REALM")
    client_id = os.environ.get("KEYCLOAK_CLIENT_ID")

    if not all([server_url, realm, client_id]):
        logger.info("Keycloak not configured, using local JWT only")
        return None

    return KeycloakConfig(
        server_url=server_url,
        realm=realm,
        client_id=client_id,
        client_secret=os.environ.get("KEYCLOAK_CLIENT_SECRET"),
        verify_ssl=os.environ.get("KEYCLOAK_VERIFY_SSL", "true").lower() == "true"
    )


def get_authenticator() -> HybridAuthenticator:
    """
    Get configured authenticator instance.

    Uses environment variables to determine configuration.
    """
    keycloak_config = get_keycloak_config_from_env()

    # JWT_SECRET is required - no default fallback in production
    jwt_secret = os.environ.get("JWT_SECRET")
    environment = os.environ.get("ENVIRONMENT", "development")

    if not jwt_secret and environment == "production":
        raise KeycloakConfigError(
            "JWT_SECRET environment variable is required in production"
        )

    return HybridAuthenticator(
        keycloak_config=keycloak_config,
        local_jwt_secret=jwt_secret,
        environment=environment
    )


# =============================================
# FASTAPI DEPENDENCY
# =============================================

# Global authenticator instance (lazy-initialized)
_authenticator: Optional[HybridAuthenticator] = None


def get_auth() -> HybridAuthenticator:
    """Get or create global authenticator."""
    global _authenticator
    if _authenticator is None:
        _authenticator = get_authenticator()
    return _authenticator


async def get_current_user(request: Request) -> Dict[str, Any]:
    """
    FastAPI dependency to get current authenticated user.

    Usage:
        @app.get("/api/protected")
        async def protected_endpoint(user: dict = Depends(get_current_user)):
            return {"user_id": user["user_id"]}
    """
    auth_header = request.headers.get("authorization", "")

    if not auth_header.startswith("Bearer "):
        # Check for development mode
        environment = os.environ.get("ENVIRONMENT", "development")
        if environment == "development":
            # Return demo user in development without token
            return {
                "user_id": "10000000-0000-0000-0000-000000000024",
                "email": "demo@breakpilot.app",
                "role": "admin",
                "realm_roles": ["admin"],
                "tenant_id": "a0000000-0000-0000-0000-000000000001",
                "auth_method": "development_bypass"
            }
        raise HTTPException(status_code=401, detail="Missing authorization header")

    token = auth_header.split(" ")[1]

    try:
        auth = get_auth()
        return await auth.validate_token(token)
    except TokenExpiredError:
        raise HTTPException(status_code=401, detail="Token expired")
    except TokenInvalidError as e:
        raise HTTPException(status_code=401, detail=str(e))
    except Exception as e:
        logger.error(f"Authentication failed: {e}")
        raise HTTPException(status_code=401, detail="Authentication failed")


async def require_role(required_role: str):
    """
    FastAPI dependency factory for role-based access.

    Usage:
        @app.get("/api/admin-only")
        async def admin_endpoint(user: dict = Depends(require_role("admin"))):
            return {"message": "Admin access granted"}
    """
    async def role_checker(user: dict = Depends(get_current_user)) -> dict:
        user_role = user.get("role", "user")
        realm_roles = user.get("realm_roles", [])

        if user_role == required_role or required_role in realm_roles:
            return user

        raise HTTPException(
            status_code=403,
            detail=f"Role '{required_role}' required"
        )

    return role_checker
