"""
FastAPI dependencies for authentication and authorization

Provides reusable dependencies for protecting endpoints.
"""

from typing import List, Optional
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from sqlalchemy.orm import Session

from .models import User
from .jwt_manager import JWTManager
from .config import AuthConfig


security = HTTPBearer()


class AuthDependencies:
    """
    FastAPI dependencies for authentication
    
    Provides dependency injection for protected endpoints.
    """
    
    def __init__(self, config: AuthConfig, get_db):
        """
        Initialize dependencies
        
        Args:
            config: Auth configuration
            get_db: Function that returns database session
        """
        self.config = config
        self.get_db = get_db
        self.jwt_manager = JWTManager(config)
    
    async def get_current_user(
        self,
        credentials: HTTPAuthorizationCredentials = Depends(security),
        db: Session = Depends(lambda: None)
    ) -> User:
        """
        Get current authenticated user from JWT token
        
        Usage:
            @app.get("/profile")
            async def profile(user: User = Depends(get_current_user)):
                return {"email": user.email}
        
        Raises:
            HTTPException: 401 if token is invalid or user not found
        """
        if db is None:
            db = next(self.get_db())
        
        token = credentials.credentials
        
        try:
            # Decode JWT (Rust)
            claims = self.jwt_manager.decode_access_token(token)
            user_id = int(claims["sub"])
        except Exception as e:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Invalid authentication credentials",
                headers={"WWW-Authenticate": "Bearer"},
            )
        
        # Get user from database
        user = db.query(User).filter_by(id=user_id).first()
        if not user:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="User not found",
                headers={"WWW-Authenticate": "Bearer"},
            )
        
        return user
    
    async def get_current_active_user(
        self,
        user: User = Depends(lambda: None)
    ) -> User:
        """
        Get current authenticated and active user
        
        Usage:
            @app.get("/dashboard")
            async def dashboard(user: User = Depends(get_current_active_user)):
                return {"welcome": user.email}
        
        Raises:
            HTTPException: 403 if user is inactive
        """
        if user is None:
            user = await self.get_current_user()
        
        if not user.is_active:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Inactive user"
            )
        
        return user
    
    async def get_current_verified_user(
        self,
        user: User = Depends(lambda: None)
    ) -> User:
        """
        Get current authenticated, active, and verified user
        
        Usage:
            @app.post("/post")
            async def create_post(user: User = Depends(get_current_verified_user)):
                return {"created_by": user.email}
        
        Raises:
            HTTPException: 403 if user is not verified
        """
        if user is None:
            user = await self.get_current_active_user()
        
        if not user.is_verified:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Email not verified"
            )
        
        return user
    
    def require_role(self, role_name: str):
        """
        Dependency factory for requiring specific role
        
        Usage:
            @app.get("/admin")
            async def admin_panel(user: User = Depends(require_role("admin"))):
                return {"message": "Welcome admin"}
        
        Args:
            role_name: Required role name
        
        Returns:
            Dependency function
        """
        async def role_checker(user: User = Depends(self.get_current_active_user)) -> User:
            if not user.has_role(role_name):
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail=f"Role '{role_name}' required"
                )
            return user
        
        return role_checker
    
    def require_any_role(self, role_names: List[str]):
        """
        Dependency factory for requiring any of specified roles
        
        Usage:
            @app.get("/moderate")
            async def moderate(user: User = Depends(require_any_role(["admin", "moderator"]))):
                return {"can_moderate": True}
        
        Args:
            role_names: List of acceptable role names
        
        Returns:
            Dependency function
        """
        async def role_checker(user: User = Depends(self.get_current_active_user)) -> User:
            if not user.has_any_role(role_names):
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail=f"One of roles {role_names} required"
                )
            return user
        
        return role_checker


# Convenience function to create dependencies
def create_auth_dependencies(config: AuthConfig, get_db) -> AuthDependencies:
    """
    Create authentication dependencies for FastAPI app
    
    Args:
        config: Auth configuration
        get_db: Database session generator function
    
    Returns:
        AuthDependencies instance
    
    Example:
        >>> from irene_auth import create_auth_dependencies, AuthConfig
        >>> 
        >>> config = AuthConfig(...)
        >>> deps = create_auth_dependencies(config, get_db)
        >>> 
        >>> @app.get("/protected")
        >>> async def protected(user = Depends(deps.get_current_user)):
        ...     return user
    """
    return AuthDependencies(config, get_db)


# Shorthand exports
def get_current_user(config: AuthConfig, get_db):
    """Get current user dependency"""
    deps = create_auth_dependencies(config, get_db)
    return deps.get_current_user


def get_current_active_user(config: AuthConfig, get_db):
    """Get current active user dependency"""
    deps = create_auth_dependencies(config, get_db)
    return deps.get_current_active_user


def require_role(role_name: str, config: AuthConfig, get_db):
    """Require specific role dependency"""
    deps = create_auth_dependencies(config, get_db)
    return deps.require_role(role_name)


def require_any_role(role_names: List[str], config: AuthConfig, get_db):
    """Require any of specified roles dependency"""
    deps = create_auth_dependencies(config, get_db)
    return deps.require_any_role(role_names)
