from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session

from genovation_advanced_auth.core.config import get_config
from genovation_advanced_auth.dependencies.auth import get_current_user
from genovation_advanced_auth.schemas.auth import (
    UserRegister,
    UserLogin,
    UserLoginWithMFA,
    TokenResponse,
    RefreshTokenRequest,
    MFASetupResponse,
    MFAVerifyRequest,
    MFADisableRequest,
    BackupCodesResponse
)
from genovation_advanced_auth.schemas.user import UserResponse
from genovation_advanced_auth.schemas.common import SuccessResponse
from genovation_advanced_auth.services.auth_service import AuthService
from genovation_advanced_auth.services.user_service import UserService
from genovation_advanced_auth.core.mfa import MFAManager
from genovation_advanced_auth.exceptions import (
    InvalidCredentialsError,
    InvalidMFACodeError,
    MFANotSetupError
)

router = APIRouter()


@router.post("/register", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
def register(user_data: UserRegister, db: Session = Depends(lambda: None)):
    """Register a new user."""
    config = get_config()
    auth_service = AuthService(db, config)
    
    try:
        user = auth_service.register_user(
            username=user_data.username,
            email=user_data.email,
            password=user_data.password,
            full_name=user_data.full_name
        )
        return user
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))


@router.post("/login", response_model=TokenResponse)
def login(credentials: UserLogin, db: Session = Depends(lambda: None)):
    """Login with username and password."""
    config = get_config()
    auth_service = AuthService(db, config)
    
    try:
        user, requires_mfa = auth_service.authenticate_user(
            username=credentials.username,
            password=credentials.password
        )
        
        if requires_mfa:
            return TokenResponse(
                access_token="",
                refresh_token="",
                requires_mfa=True,
                message="MFA verification required",
                next_step="/auth/login/mfa"
            )
        
        tokens = auth_service.create_tokens(user)
        return TokenResponse(**tokens, requires_mfa=False, message="Login successful")
        
    except InvalidCredentialsError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid credentials"
        )


@router.post("/login/mfa", response_model=TokenResponse)
def login_with_mfa(credentials: UserLoginWithMFA, db: Session = Depends(lambda: None)):
    """Login with username, password, and MFA code."""
    config = get_config()
    auth_service = AuthService(db, config)
    user_service = UserService(db, config)
    
    try:
        user, requires_mfa = auth_service.authenticate_user(
            username=credentials.username,
            password=credentials.password
        )
        
        if not requires_mfa:
            raise HTTPException(
                status_code=400,
                detail="MFA not enabled. Use /login endpoint"
            )
        
        if not credentials.mfa_code:
            raise HTTPException(status_code=400, detail="MFA code required")
        
        user_service.verify_mfa_code(user.id, credentials.mfa_code)
        tokens = auth_service.create_tokens(user)
        
        return TokenResponse(**tokens, requires_mfa=False)
        
    except (InvalidCredentialsError, InvalidMFACodeError):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid credentials or MFA code"
        )
    except MFANotSetupError:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="MFA is not enabled"
        )


@router.post("/refresh", response_model=TokenResponse)
def refresh_token(request: RefreshTokenRequest, db: Session = Depends(lambda: None)):
    """Refresh access token."""
    config = get_config()
    auth_service = AuthService(db, config)
    
    try:
        tokens = auth_service.refresh_access_token(request.refresh_token)
        return TokenResponse(**tokens, requires_mfa=False)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid refresh token"
        )


@router.post("/mfa/setup", response_model=MFASetupResponse)
def setup_mfa(
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(lambda: None)
):
    """Setup MFA for current user."""
    config = get_config()
    user_service = UserService(db, config)
    mfa_manager = MFAManager(config)
    
    setup_data = user_service.setup_mfa(current_user["id"])
    qr_code = mfa_manager.generate_qr_code_base64(setup_data["provisioning_uri"])
    
    return MFASetupResponse(
        secret=setup_data["secret"],
        provisioning_uri=setup_data["provisioning_uri"],
        qr_code=qr_code,
        backup_codes=setup_data["backup_codes"]
    )


@router.post("/mfa/verify", response_model=SuccessResponse)
def verify_mfa(
    request: MFAVerifyRequest,
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(lambda: None)
):
    """Verify MFA code and enable MFA."""
    config = get_config()
    user_service = UserService(db, config)
    
    try:
        user_service.verify_and_enable_mfa(current_user["id"], request.code)
        return SuccessResponse(success=True, message="MFA enabled successfully")
    except InvalidMFACodeError:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid MFA code"
        )


@router.post("/mfa/disable", response_model=SuccessResponse)
def disable_mfa(
    request: MFADisableRequest,
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(lambda: None)
):
    """Disable MFA for current user."""
    config = get_config()
    user_service = UserService(db, config)
    
    try:
        user_service.disable_mfa(current_user["id"], request.password)
        return SuccessResponse(success=True, message="MFA disabled successfully")
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))


@router.post("/mfa/backup-codes", response_model=BackupCodesResponse)
def regenerate_backup_codes(
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(lambda: None)
):
    """Regenerate backup codes."""
    config = get_config()
    user_service = UserService(db, config)
    
    backup_codes = user_service.regenerate_backup_codes(current_user["id"])
    return BackupCodesResponse(backup_codes=backup_codes)
