from fastapi import APIRouter, Depends, HTTPException, status, Cookie, Response, Request, UploadFile, File
from fastapi.responses import JSONResponse
from sqlalchemy.orm import Session
from pathlib import Path
from datetime import datetime
import aiofiles
import uuid
import os
from ...shared.config.database import get_db
from ..services.auth_service import auth_service
from ..services.session_service import session_service
from ..schemas.auth import RegisterRequest, LoginRequest, RefreshTokenRequest, ForgotPasswordRequest, ResetPasswordRequest, AuthResponse, TokenResponse, MessageResponse, MFAInitResponse, EnableMFARequest, VerifyMFARequest, MFAStatusResponse, UpdateProfileRequest
from ...security.middleware.auth import get_current_user
from ..models.user import User
from ...analytics.services.audit_service import audit_service
from ...shared.config.logging_config import get_logger
from ...payments.services.accountant_security_service import accountant_security_service
from ...auth.services.mfa_service import mfa_service
from ...shared.utils.role_helpers import is_admin
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
from functools import wraps

router = APIRouter(prefix='/auth', tags=['auth'])
logger = get_logger(__name__)

# Stricter rate limits for authentication endpoints
AUTH_RATE_LIMIT = "5/minute"  # 5 attempts per minute per IP
PASSWORD_RESET_LIMIT = "3/hour"  # 3 password reset requests per hour per IP
LOGIN_RATE_LIMIT = "10/minute"  # 10 login attempts per minute per IP

# Initialize limiter - will be set from app state
limiter = None

def get_limiter(request: Request) -> Limiter:
    """Get limiter instance from app state."""
    global limiter
    if hasattr(request.app.state, 'limiter'):
        limiter = request.app.state.limiter
    return limiter


def get_base_url(request: Request) -> str:
    return os.getenv('SERVER_URL') or f'http://{request.headers.get('host', 'localhost:8000')}'

def normalize_image_url(image_url: str, base_url: str) -> str:
    if not image_url:
        return image_url
    if image_url.startswith('http://') or image_url.startswith('https://'):
        return image_url
    if image_url.startswith('/'):
        return f'{base_url}{image_url}'
    return f'{base_url}/{image_url}'

@router.post('/register', status_code=status.HTTP_201_CREATED)
async def register(
    request: Request, 
    register_request: RegisterRequest, 
    response: Response, 
    db: Session=Depends(get_db)
):
    # Rate limiting is handled by middleware, but we can add additional checks here if needed
    client_ip = request.client.host if request.client else None
    user_agent = request.headers.get('User-Agent')
    request_id = getattr(request.state, 'request_id', None)
    
    try:
        result = await auth_service.register(db=db, name=register_request.name, email=register_request.email, password=register_request.password, phone=register_request.phone)
        from ...shared.config.settings import settings
        max_age = 7 * 24 * 60 * 60  # 7 days for registration
        # Use secure cookies in production (HTTPS required)
        # Set access token in httpOnly cookie for security
        # Use 'lax' in development for cross-origin support, 'strict' in production
        samesite_value = 'strict' if settings.is_production else 'lax'
        response.set_cookie(
            key='accessToken', 
            value=result['token'], 
            httponly=True, 
            secure=settings.is_production,  # Secure flag enabled in production
            samesite=samesite_value, 
            max_age=max_age, 
            path='/'
        )
        # Set refresh token in httpOnly cookie
        response.set_cookie(
            key='refreshToken', 
            value=result['refreshToken'], 
            httponly=True, 
            secure=settings.is_production,  # Secure flag enabled in production
            samesite=samesite_value, 
            max_age=max_age, 
            path='/'
        )
        
        # Create user session for new registration
        try:
            # Extract device info from user agent
            device_info = None
            if user_agent:
                device_info = {'user_agent': user_agent}
            
            session_service.create_session(
                db=db,
                user_id=result['user']['id'],
                ip_address=client_ip,
                user_agent=user_agent,
                device_info=str(device_info) if device_info else None
            )
        except Exception as e:
            # Log error but don't fail registration if session creation fails
            logger.warning(f'Failed to create session during registration: {str(e)}')
        
        # Log successful registration
        await audit_service.log_action(
            db=db,
            action='user_registered',
            resource_type='user',
            user_id=result['user']['id'],
            ip_address=client_ip,
            user_agent=user_agent,
            request_id=request_id,
            details={'email': register_request.email, 'name': register_request.name},
            status='success'
        )
        
        # Return user data but NOT the token (it's in httpOnly cookie now)
        return {'status': 'success', 'message': 'Registration successful', 'data': {'user': result['user']}}
    except ValueError as e:
        error_message = str(e)
        # Log failed registration attempt
        await audit_service.log_action(
            db=db,
            action='user_registration_failed',
            resource_type='user',
            ip_address=client_ip,
            user_agent=user_agent,
            request_id=request_id,
            details={'email': register_request.email, 'name': register_request.name},
            status='failed',
            error_message=error_message
        )
        return JSONResponse(status_code=status.HTTP_400_BAD_REQUEST, content={'status': 'error', 'message': error_message})

@router.post('/login')
async def login(
    request: Request,
    login_request: LoginRequest, 
    response: Response, 
    db: Session=Depends(get_db)
):
    client_ip = request.client.host if request.client else None
    user_agent = request.headers.get('User-Agent')
    request_id = getattr(request.state, 'request_id', None)
    
    try:
        result = await auth_service.login(
            db=db, 
            email=login_request.email, 
            password=login_request.password, 
            remember_me=login_request.rememberMe or False, 
            mfa_token=login_request.mfaToken,
            expected_role=login_request.expectedRole
        )
        
        # After successful login, check if user is accountant and enforce MFA
        requires_mfa_setup = False
        if result.get('user') and not result.get('requires_mfa'):
            user = db.query(User).filter(User.id == result['user']['id']).first()
            if user:
                try:
                    from ...payments.services.accountant_security_service import accountant_security_service
                    from ...shared.utils.role_helpers import is_accountant
                    
                    if is_accountant(user, db):
                        # Check if MFA is required but not enabled
                        is_enforced, reason = accountant_security_service.is_mfa_enforced(user, db)
                        if not is_enforced:
                            # MFA required but not enabled - allow login but flag for setup
                            requires_mfa_setup = True
                            await audit_service.log_action(
                                db=db,
                                action='login_mfa_setup_required',
                                resource_type='authentication',
                                user_id=user.id,
                                ip_address=client_ip,
                                user_agent=user_agent,
                                request_id=request_id,
                                details={'email': login_request.email, 'reason': reason},
                                status='success'
                            )
                            logger.info(f'User {user.id} logged in but MFA setup required: {reason}')
                        else:
                            # MFA is enabled and enforced - create accountant session for tracking
                            try:
                                accountant_security_service.create_session(
                                    db=db,
                                    user_id=user.id,
                                    ip_address=client_ip,
                                    user_agent=user_agent,
                                    device_fingerprint=None  # Can be enhanced with device fingerprinting
                                )
                                
                                # Log login activity
                                is_unusual = accountant_security_service.detect_unusual_activity(
                                    db=db,
                                    user_id=user.id,
                                    ip_address=client_ip
                                )
                                
                                accountant_security_service.log_activity(
                                    db=db,
                                    user_id=user.id,
                                    activity_type='login',
                                    activity_description='Accountant login successful',
                                    ip_address=client_ip,
                                    user_agent=user_agent,
                                    risk_level='low',
                                    is_unusual=is_unusual
                                )
                            except Exception as e:
                                logger.warning(f'Error creating accountant session: {e}')
                except Exception as e:
                    logger.warning(f'Error enforcing MFA for accountant: {e}')
        if result.get('requires_mfa'):
            # Log MFA required
            user = db.query(User).filter(User.email == login_request.email.lower().strip()).first()
            if user:
                # Validate role even for MFA flow if expected_role is provided
                if login_request.expectedRole and user.role:
                    user_role = user.role.name.lower() if hasattr(user.role, 'name') else None
                    expected_role = login_request.expectedRole.lower()
                    if user_role != expected_role:
                        await audit_service.log_action(
                            db=db,
                            action='login_role_mismatch',
                            resource_type='authentication',
                            user_id=user.id,
                            ip_address=client_ip,
                            user_agent=user_agent,
                            request_id=request_id,
                            details={'email': login_request.email, 'expected_role': expected_role, 'actual_role': user_role},
                            status='failed'
                        )
                        return JSONResponse(
                            status_code=status.HTTP_403_FORBIDDEN,
                            content={'status': 'error', 'message': f'This login endpoint is only for {expected_role} users'}
                        )
                
                await audit_service.log_action(
                    db=db,
                    action='login_mfa_required',
                    resource_type='authentication',
                    user_id=user.id,
                    ip_address=client_ip,
                    user_agent=user_agent,
                    request_id=request_id,
                    details={'email': login_request.email},
                    status='success'
                )
            return {'status': 'success', 'requires_mfa': True, 'user_id': result['user_id']}
        
        # After successful login (MFA passed if required), handle role-specific security
        if not requires_mfa_setup:
            user = db.query(User).filter(User.id == result['user']['id']).first()
            if user:
                try:
                    from ...payments.services.accountant_security_service import accountant_security_service
                    from ...auth.services.admin_security_service import admin_security_service
                    from ...shared.utils.role_helpers import is_accountant, is_admin
                    from ...shared.config.settings import settings
                    
                    # Handle accountant role
                    if is_accountant(user, db):
                        # Check if MFA is required but not enabled
                        is_enforced, reason = accountant_security_service.is_mfa_enforced(user, db)
                        if not is_enforced:
                            # MFA required but not enabled - allow login but flag for setup
                            requires_mfa_setup = True
                            await audit_service.log_action(
                                db=db,
                                action='login_mfa_setup_required',
                                resource_type='authentication',
                                user_id=user.id,
                                ip_address=client_ip,
                                user_agent=user_agent,
                                request_id=request_id,
                                details={'email': login_request.email, 'reason': reason},
                                status='success'
                            )
                            logger.info(f'User {user.id} logged in but MFA setup required: {reason}')
                        # Always create an accountant security session so step-up auth works
                        try:
                            accountant_session = accountant_security_service.create_session(
                                db=db,
                                user_id=user.id,
                                ip_address=client_ip,
                                user_agent=user_agent,
                                device_fingerprint=None
                            )
                            
                            db.commit()
                            
                            # Store session_token in cookie for step-up authentication
                            session_max_age = 4 * 60 * 60  # 4 hours
                            samesite_value = 'strict' if settings.is_production else 'lax'
                            response.set_cookie(
                                key='session_token',
                                value=accountant_session.session_token,
                                httponly=True,
                                secure=settings.is_production,
                                samesite=samesite_value,
                                max_age=session_max_age,
                                path='/'
                            )
                            
                            # Log login activity
                            is_unusual = accountant_security_service.detect_unusual_activity(
                                db=db,
                                user_id=user.id,
                                ip_address=client_ip
                            )
                            
                            accountant_security_service.log_activity(
                                db=db,
                                user_id=user.id,
                                activity_type='login',
                                activity_description='Accountant login successful',
                                ip_address=client_ip,
                                user_agent=user_agent,
                                risk_level='low',
                                is_unusual=is_unusual
                            )
                        except Exception as e:
                            db.rollback()
                            logger.warning(f'Error creating accountant session: {e}')
                    
                    # Handle admin role (separate from accountant)
                    elif is_admin(user, db):
                        try:
                            admin_session = admin_security_service.create_session(
                                db=db,
                                user_id=user.id,
                                ip_address=client_ip,
                                user_agent=user_agent,
                                device_fingerprint=None
                            )
                            
                            db.commit()
                            
                            # Store admin session_token in cookie for step-up authentication
                            session_max_age = 8 * 60 * 60  # 8 hours
                            samesite_value = 'strict' if settings.is_production else 'lax'
                            response.set_cookie(
                                key='admin_session_token',
                                value=admin_session.session_token,
                                httponly=True,
                                secure=settings.is_production,
                                samesite=samesite_value,
                                max_age=session_max_age,
                                path='/'
                            )
                            
                            # Log login activity
                            is_unusual = admin_security_service.detect_unusual_activity(
                                db=db,
                                user_id=user.id,
                                ip_address=client_ip
                            )
                            
                            admin_security_service.log_activity(
                                db=db,
                                user_id=user.id,
                                activity_type='login',
                                activity_description='Admin login successful',
                                ip_address=client_ip,
                                user_agent=user_agent,
                                risk_level='low',
                                is_unusual=is_unusual
                            )
                        except Exception as e:
                            db.rollback()
                            logger.warning(f'Error creating admin session: {e}')
                except Exception as e:
                    logger.warning(f'Error handling role-specific security: {e}')
        
        from ...shared.config.settings import settings
        max_age = 7 * 24 * 60 * 60 if login_request.rememberMe else 1 * 24 * 60 * 60
        # Use secure cookies in production (HTTPS required)
        # Set access token in httpOnly cookie for security
        # Use 'lax' in development for cross-origin support, 'strict' in production
        samesite_value = 'strict' if settings.is_production else 'lax'
        response.set_cookie(
            key='accessToken', 
            value=result['token'], 
            httponly=True, 
            secure=settings.is_production,  # Secure flag enabled in production
            samesite=samesite_value, 
            max_age=max_age, 
            path='/'
        )
        # Set refresh token in httpOnly cookie
        response.set_cookie(
            key='refreshToken', 
            value=result['refreshToken'], 
            httponly=True, 
            secure=settings.is_production,  # Secure flag enabled in production
            samesite=samesite_value, 
            max_age=max_age, 
            path='/'
        )
        
        # Create user session
        try:
            # Extract device info from user agent
            device_info = None
            if user_agent:
                device_info = {'user_agent': user_agent}
            
            session_service.create_session(
                db=db,
                user_id=result['user']['id'],
                ip_address=client_ip,
                user_agent=user_agent,
                device_info=str(device_info) if device_info else None
            )
        except Exception as e:
            # Log error but don't fail login if session creation fails
            logger.warning(f'Failed to create session during login: {str(e)}')
        
        # Validate role if expected_role is provided (for role-specific login endpoints)
        if login_request.expectedRole:
            user_role = result['user'].get('role', '').lower()
            expected_role = login_request.expectedRole.lower()
            if user_role != expected_role:
                # Log security event
                await audit_service.log_action(
                    db=db,
                    action='login_role_mismatch',
                    resource_type='authentication',
                    user_id=result['user']['id'],
                    ip_address=client_ip,
                    user_agent=user_agent,
                    request_id=request_id,
                    details={'email': login_request.email, 'expected_role': expected_role, 'actual_role': user_role},
                    status='failed'
                )
                # Clear cookies on role mismatch
                response.delete_cookie(key='refreshToken', path='/', secure=settings.is_production, samesite=samesite_value)
                response.delete_cookie(key='accessToken', path='/', secure=settings.is_production, samesite=samesite_value)
                return JSONResponse(
                    status_code=status.HTTP_403_FORBIDDEN,
                    content={'status': 'error', 'message': f'This login endpoint is only for {expected_role} users'}
                )
        
        # Log successful login
        await audit_service.log_action(
            db=db,
            action='login_success',
            resource_type='authentication',
            user_id=result['user']['id'],
            ip_address=client_ip,
            user_agent=user_agent,
            request_id=request_id,
            details={'email': login_request.email, 'remember_me': login_request.rememberMe},
            status='success'
        )
        
        # Return user data but NOT the token (it's in httpOnly cookie now)
        response_data = {'status': 'success', 'data': {'user': result['user']}}
        if requires_mfa_setup:
            response_data['requires_mfa_setup'] = True
            response_data['message'] = 'MFA setup is required for your role. Please enable MFA in your profile settings.'
        return response_data
    except ValueError as e:
        error_message = str(e)
        # SECURITY: Sanitize error messages to prevent information disclosure
        # Don't reveal specific details about account status, remaining attempts, etc. to unauthenticated users
        sanitized_message = error_message
        
        # Generic error messages for authentication failures
        if 'Invalid email or password' in error_message or 'Invalid MFA token' in error_message:
            sanitized_message = 'Invalid email or password'
            status_code = status.HTTP_401_UNAUTHORIZED
        elif 'Account is disabled' in error_message:
            sanitized_message = 'Account is disabled. Please contact support.'
            status_code = status.HTTP_403_FORBIDDEN
        elif 'Account is temporarily locked' in error_message or 'Account has been temporarily locked' in error_message:
            # Keep lockout message but remove specific timing details for security
            sanitized_message = 'Account is temporarily locked due to multiple failed login attempts. Please try again later.'
            status_code = status.HTTP_403_FORBIDDEN
        else:
            status_code = status.HTTP_400_BAD_REQUEST
        
        # Log failed login attempt with full details (for internal logging)
        await audit_service.log_action(
            db=db,
            action='login_failed',
            resource_type='authentication',
            ip_address=client_ip,
            user_agent=user_agent,
            request_id=request_id,
            details={'email': login_request.email},
            status='failed',
            error_message=error_message  # Log full error internally
        )
        
        return JSONResponse(status_code=status_code, content={'status': 'error', 'message': sanitized_message})

@router.post('/refresh-token', response_model=TokenResponse)
async def refresh_token(
    request: Request,
    response: Response,
    refreshToken: str=Cookie(None),
    db: Session=Depends(get_db)
):
    if not refreshToken:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail='Refresh token not found')
    try:
        result = await auth_service.refresh_access_token(db, refreshToken)
        from ...shared.config.settings import settings
        # Set new access token in httpOnly cookie
        # Use 'lax' in development for cross-origin support, 'strict' in production
        samesite_value = 'strict' if settings.is_production else 'lax'
        max_age = 7 * 24 * 60 * 60  # 7 days
        response.set_cookie(
            key='accessToken',
            value=result['token'],
            httponly=True,
            secure=settings.is_production,
            samesite=samesite_value,
            max_age=max_age,
            path='/'
        )
        # Return user data but NOT the token (it's in httpOnly cookie now)
        return {'status': 'success', 'data': {'user': result.get('user')}}
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=str(e))

@router.post('/logout', response_model=MessageResponse)
async def logout(
    request: Request,
    response: Response, 
    refreshToken: str=Cookie(None), 
    current_user: User=Depends(get_current_user),
    db: Session=Depends(get_db)
):
    client_ip = request.client.host if request.client else None
    user_agent = request.headers.get('User-Agent')
    request_id = getattr(request.state, 'request_id', None)
    
    if refreshToken:
        await auth_service.logout(db, refreshToken)
    
    # Delete both access and refresh token cookies
    from ...shared.config.settings import settings
    # Use 'lax' in development for cross-origin support, 'strict' in production
    samesite_value = 'strict' if settings.is_production else 'lax'
    response.delete_cookie(key='refreshToken', path='/', secure=settings.is_production, samesite=samesite_value)
    response.delete_cookie(key='accessToken', path='/', secure=settings.is_production, samesite=samesite_value)
    
    # Log logout
    await audit_service.log_action(
        db=db,
        action='logout',
        resource_type='authentication',
        user_id=current_user.id,
        ip_address=client_ip,
        user_agent=user_agent,
        request_id=request_id,
        details={'email': current_user.email},
        status='success'
    )
    
    return {'status': 'success', 'message': 'Logout successful'}

@router.get('/profile')
async def get_profile(current_user: User=Depends(get_current_user), db: Session=Depends(get_db)):
    try:
        user = await auth_service.get_profile(db, current_user.id)
        return {'status': 'success', 'data': {'user': user}}
    except ValueError as e:
        if 'User not found' in str(e):
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))

@router.put('/profile')
async def update_profile(
    request: Request,
    profile_data: UpdateProfileRequest, 
    current_user: User=Depends(get_current_user), 
    db: Session=Depends(get_db)
):
    # Rate limiting is handled by global middleware (slowapi)
    # The global rate limiter applies default limits to all endpoints
    # For stricter limits on profile updates, configure in settings or use endpoint-specific limits
    client_ip = request.client.host if request.client else None
    user_agent = request.headers.get('User-Agent')
    request_id = getattr(request.state, 'request_id', None)
    
    try:
        # Track if password is being changed for audit logging
        password_changed = bool(profile_data.password)
        email_changed = bool(profile_data.email and profile_data.email != current_user.email)
        
        user = await auth_service.update_profile(
            db=db, 
            user_id=current_user.id, 
            full_name=profile_data.full_name, 
            email=profile_data.email, 
            phone_number=profile_data.phone_number, 
            password=profile_data.password, 
            current_password=profile_data.currentPassword, 
            currency=profile_data.currency
        )
        
        # Audit logging for sensitive profile changes
        if password_changed:
            await audit_service.log_action(
                db=db,
                action='user_password_changed',
                resource_type='user',
                user_id=current_user.id,
                resource_id=current_user.id,
                ip_address=client_ip,
                user_agent=user_agent,
                request_id=request_id,
                details={'user_email': current_user.email},
                status='success'
            )
        
        if email_changed:
            await audit_service.log_action(
                db=db,
                action='user_email_change_requested',
                resource_type='user',
                user_id=current_user.id,
                resource_id=current_user.id,
                ip_address=client_ip,
                user_agent=user_agent,
                request_id=request_id,
                details={'old_email': current_user.email, 'new_email': profile_data.email},
                status='success'
            )
        
        return {'status': 'success', 'message': 'Profile updated successfully', 'data': {'user': user}}
    except ValueError as e:
        error_message = str(e)
        status_code = status.HTTP_400_BAD_REQUEST
        if 'not found' in error_message.lower():
            status_code = status.HTTP_404_NOT_FOUND
        raise HTTPException(status_code=status_code, detail=error_message)
    except Exception as e:
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail='An error occurred while updating your profile. Please try again.')

@router.post('/forgot-password', response_model=MessageResponse)
async def forgot_password(request: ForgotPasswordRequest, db: Session=Depends(get_db)):
    result = await auth_service.forgot_password(db, request.email)
    return {'status': 'success', 'message': result['message']}

@router.post('/reset-password', response_model=MessageResponse)
async def reset_password(request: Request, reset_request: ResetPasswordRequest, db: Session=Depends(get_db)):
    client_ip = request.client.host if request.client else None
    user_agent = request.headers.get('User-Agent')
    request_id = getattr(request.state, 'request_id', None)
    
    try:
        result = await auth_service.reset_password(db=db, token=reset_request.token, password=reset_request.password)
        
        # Get user ID from reset token for audit logging
        from ..models.password_reset_token import PasswordResetToken
        import hashlib
        hashed_token = hashlib.sha256(reset_request.token.encode()).hexdigest()
        reset_token_obj = db.query(PasswordResetToken).filter(
            PasswordResetToken.token == hashed_token
        ).first()
        
        if reset_token_obj:
            await audit_service.log_action(
                db=db,
                action='user_password_reset',
                resource_type='user',
                user_id=reset_token_obj.user_id,
                resource_id=reset_token_obj.user_id,
                ip_address=client_ip,
                user_agent=user_agent,
                request_id=request_id,
                details={'reset_method': 'token'},
                status='success'
            )
        
        return {'status': 'success', 'message': result['message']}
    except ValueError as e:
        status_code = status.HTTP_400_BAD_REQUEST
        if 'User not found' in str(e):
            status_code = status.HTTP_404_NOT_FOUND
        raise HTTPException(status_code=status_code, detail=str(e))

@router.post('/verify-email/{token}', response_model=MessageResponse)
async def verify_email(token: str, db: Session=Depends(get_db)):
    """Verify email address using verification token."""
    try:
        result = await auth_service.verify_email(db=db, token=token)
        return {'status': 'success', 'message': result['message']}
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
    except Exception as e:
        logger.error(f'Error verifying email: {str(e)}', exc_info=True)
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail='An error occurred while verifying your email')

@router.post('/resend-verification', response_model=MessageResponse)
async def resend_verification(current_user: User=Depends(get_current_user), db: Session=Depends(get_db)):
    """Resend email verification link."""
    try:
        result = await auth_service.resend_verification_email(db=db, user_id=current_user.id)
        return {'status': 'success', 'message': result['message']}
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
    except Exception as e:
        logger.error(f'Error resending verification email: {str(e)}', exc_info=True)
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail='An error occurred while resending verification email')

from ..services.mfa_service import mfa_service
from ...shared.config.settings import settings

@router.get('/mfa/init')
async def init_mfa(current_user: User=Depends(get_current_user), db: Session=Depends(get_db)):
    try:
        if current_user.mfa_enabled:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='MFA is already enabled')
        secret = mfa_service.generate_secret()
        app_name = getattr(settings, 'APP_NAME', 'Hotel Booking')
        qr_code = mfa_service.generate_qr_code(secret, current_user.email, app_name)
        return {'status': 'success', 'data': {'secret': secret, 'qr_code': qr_code}}
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f'Error initializing MFA: {str(e)}')

@router.post('/mfa/enable')
async def enable_mfa(request: Request, mfa_request: EnableMFARequest, current_user: User=Depends(get_current_user), db: Session=Depends(get_db)):
    client_ip = request.client.host if request.client else None
    user_agent = request.headers.get('User-Agent')
    request_id = getattr(request.state, 'request_id', None)
    
    try:
        success, backup_codes = mfa_service.enable_mfa(db=db, user_id=current_user.id, secret=mfa_request.secret, verification_token=mfa_request.verification_token)
        
        # Audit logging for MFA enable
        await audit_service.log_action(
            db=db,
            action='user_mfa_enabled',
            resource_type='user',
            user_id=current_user.id,
            resource_id=current_user.id,
            ip_address=client_ip,
            user_agent=user_agent,
            request_id=request_id,
            details={'user_email': current_user.email},
            status='success'
        )
        
        return {'status': 'success', 'message': 'MFA enabled successfully', 'data': {'backup_codes': backup_codes}}
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f'Error enabling MFA: {str(e)}')

@router.post('/mfa/disable')
async def disable_mfa(request: Request, current_user: User=Depends(get_current_user), db: Session=Depends(get_db)):
    client_ip = request.client.host if request.client else None
    user_agent = request.headers.get('User-Agent')
    request_id = getattr(request.state, 'request_id', None)
    
    try:
        mfa_service.disable_mfa(db=db, user_id=current_user.id)
        
        # Audit logging for MFA disable
        await audit_service.log_action(
            db=db,
            action='user_mfa_disabled',
            resource_type='user',
            user_id=current_user.id,
            resource_id=current_user.id,
            ip_address=client_ip,
            user_agent=user_agent,
            request_id=request_id,
            details={'user_email': current_user.email},
            status='success'
        )
        
        return {'status': 'success', 'message': 'MFA disabled successfully'}
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f'Error disabling MFA: {str(e)}')

@router.get('/mfa/status', response_model=MFAStatusResponse)
async def get_mfa_status(current_user: User=Depends(get_current_user), db: Session=Depends(get_db)):
    try:
        status_data = mfa_service.get_mfa_status(db=db, user_id=current_user.id)
        return status_data
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f'Error getting MFA status: {str(e)}')

@router.post('/mfa/regenerate-backup-codes')
async def regenerate_backup_codes(current_user: User=Depends(get_current_user), db: Session=Depends(get_db)):
    try:
        backup_codes = mfa_service.regenerate_backup_codes(db=db, user_id=current_user.id)
        return {'status': 'success', 'message': 'Backup codes regenerated successfully', 'data': {'backup_codes': backup_codes}}
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f'Error regenerating backup codes: {str(e)}')

@router.post('/avatar/upload')
async def upload_avatar(request: Request, image: UploadFile=File(...), current_user: User=Depends(get_current_user), db: Session=Depends(get_db)):
    try:
        # Use comprehensive file validation (magic bytes + size)
        from ...shared.utils.file_validation import validate_uploaded_image
        max_avatar_size = 2 * 1024 * 1024  # 2MB for avatars
        
        # Validate file completely (MIME type, size, magic bytes, integrity)
        content = await validate_uploaded_image(image, max_avatar_size)
        
        # Optimize image before saving
        from ...shared.utils.image_optimization import optimize_image_async, ImageType
        optimized_content, optimized_ext = await optimize_image_async(content, ImageType.AVATAR)
        
        # Use same path calculation as main.py: go from Backend/src/auth/routes/auth_routes.py
        # to Backend/uploads/avatars
        upload_dir = Path(__file__).parent.parent.parent.parent / 'uploads' / 'avatars'
        upload_dir.mkdir(parents=True, exist_ok=True)
        if current_user.avatar:
            old_avatar_path = Path(__file__).parent.parent.parent.parent / current_user.avatar.lstrip('/')
            if old_avatar_path.exists() and old_avatar_path.is_file():
                try:
                    old_avatar_path.unlink()
                except Exception:
                    pass
        # Sanitize filename to prevent path traversal attacks
        from ...shared.utils.sanitization import sanitize_filename
        original_filename = image.filename or 'avatar.png'
        sanitized_filename = sanitize_filename(original_filename)
        ext = Path(sanitized_filename).suffix or optimized_ext or '.webp'
        
        # Update extension if format changed
        if optimized_ext:
            ext = optimized_ext
        
        # Generate secure filename with user ID and UUID to prevent collisions
        filename = f'avatar-{current_user.id}-{uuid.uuid4()}{ext}'
        file_path = upload_dir / filename
        async with aiofiles.open(file_path, 'wb') as f:
            await f.write(optimized_content)
        image_url = f'/uploads/avatars/{filename}'
        current_user.avatar = image_url
        db.commit()
        db.refresh(current_user)
        base_url = get_base_url(request)
        full_url = normalize_image_url(image_url, base_url)
        return {'success': True, 'status': 'success', 'message': 'Avatar uploaded successfully', 'data': {'avatar_url': image_url, 'full_url': full_url, 'user': {'id': current_user.id, 'name': current_user.full_name, 'email': current_user.email, 'phone': current_user.phone, 'avatar': image_url, 'role': current_user.role.name if current_user.role else 'customer'}}}
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f'Error uploading avatar: {str(e)}')