"""FastAPI router for authentication endpoints.

This module provides authentication endpoints with security features:
- Rate limiting (ENABLED by default - essential security)
- reCAPTCHA protection (decorators present, DISABLED by default)

To enable reCAPTCHA (optional but recommended):
1. Set RECAPTCHA_ENABLED=true in .env
2. Configure RECAPTCHA_SECRET_KEY and RECAPTCHA_SITE_KEY
3. Decorators are already applied - they become active when enabled

To disable rate limiting (NOT recommended):
- Comment out @rate_limit decorators
- Set RATE_LIMIT_ENABLED=false in .env
"""

from fastapi import APIRouter, HTTPException, Request, status

from .decorators import rate_limit, recaptcha_protected
from .dependencies import AuthServiceDep, CurrentUser
from .exceptions import (
    InvalidCredentialsError,
    InvalidTokenError,
    UserAlreadyExistsError,
    UserNotFoundError,
)
from .schemas import (
    ChangePasswordRequest,
    DeleteAccountRequest,
    ForgotPasswordRequest,
    LoginResponse,
    MessageResponse,
    ResetPasswordRequest,
    TokenRefresh,
    UserLogin,
    UserRegister,
    UserResponse,
)

# Create router
router = APIRouter()


@router.post(
    "/register",
    response_model=UserResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Register new user",
    description="Create a new user account with email and password",
    tags=["Authentication"]
)
@rate_limit("5/minute")  # Prevent registration abuse
@recaptcha_protected("register")  # Disabled by default, enable via RECAPTCHA_ENABLED=true
async def register(user_data: UserRegister, auth_service: AuthServiceDep, request: Request) -> UserResponse:
    """
    Register a new user.

    Security features:
    - ✅ Rate limiting: 5 requests/minute (enabled)
    - ⚪ reCAPTCHA: Disabled by default (enable via RECAPTCHA_ENABLED=true)
    - 💡 Recommendation: Add email verification in production
    """
    try:
        user = await auth_service.register_user(
            email=user_data.email,
            password=user_data.password,
            name=user_data.name
        )
        return UserResponse(**user.to_response())
    except UserAlreadyExistsError:
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail="User with this email already exists"
        )


@router.post(
    "/login",
    response_model=LoginResponse,
    summary="Login user",
    description="Authenticate user and return JWT tokens",
    tags=["Authentication"]
)
@rate_limit("10/minute")  # CRITICAL: Prevent brute force attacks
@recaptcha_protected("login")  # Disabled by default, enable via RECAPTCHA_ENABLED=true
async def login(
    credentials: UserLogin,
    auth_service: AuthServiceDep,
    request: Request
) -> LoginResponse:
    """
    Login user and return tokens.

    Security features:
    - ✅ Rate limiting: 10 requests/minute (enabled - CRITICAL)
    - ⚪ reCAPTCHA: Disabled by default (enable via RECAPTCHA_ENABLED=true)
    - 💡 Recommendation: Implement account lockout after N failed attempts
    """
    try:
        return await auth_service.login_user(
            email=credentials.email,
            password=credentials.password
        )
    except InvalidCredentialsError as e:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=str(e),
            headers={"WWW-Authenticate": "Bearer"},
        )


@router.post(
    "/refresh",
    response_model=dict,
    summary="Refresh access token",
    description="Get new access token using refresh token",
    tags=["Authentication"]
)
@rate_limit("20/minute")  # Prevent token refresh abuse
async def refresh_token(
    token_data: TokenRefresh,
    auth_service: AuthServiceDep,
    request: Request
) -> dict:
    """
    Refresh access token.

    Security features:
    - ✅ Rate limiting: 20 requests/minute (enabled)
    - 💡 Recommendation: Consider implementing refresh token rotation
    """
    try:
        return await auth_service.refresh_access_token(token_data.refreshToken)
    except InvalidTokenError as e:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=str(e),
            headers={"WWW-Authenticate": "Bearer"},
        )


@router.post(
    "/forgot-password",
    response_model=MessageResponse,
    summary="Request password reset",
    description="Request a password reset email (development: token is printed to console)",
    tags=["Authentication"]
)
@rate_limit("3/minute")  # CRITICAL: Prevent email enumeration and spam
@recaptcha_protected("forgot_password")  # Disabled by default, enable via RECAPTCHA_ENABLED=true
async def forgot_password(
    request_data: ForgotPasswordRequest,
    auth_service: AuthServiceDep,
    request: Request
) -> MessageResponse:
    """
    Request password reset.

    Security features:
    - ✅ Rate limiting: 3 requests/minute (enabled - CRITICAL)
    - ⚪ reCAPTCHA: Disabled by default, RECOMMENDED (enable via RECAPTCHA_ENABLED=true)
    - ✅ Generic response message (prevents email enumeration)
    """
    # Always return success message to prevent email enumeration
    await auth_service.request_password_reset(request_data.email)
    return MessageResponse(
        message="If the email exists, a password reset link has been sent"
    )


@router.post(
    "/reset-password",
    response_model=MessageResponse,
    summary="Reset password",
    description="Reset password using reset token",
    tags=["Authentication"]
)
@rate_limit("5/minute")  # Prevent token brute force
async def reset_password(
    request_data: ResetPasswordRequest,
    auth_service: AuthServiceDep,
    request: Request
) -> MessageResponse:
    """
    Reset password with token.

    Security features:
    - ✅ Rate limiting: 5 requests/minute (enabled)
    - ✅ Token is single-use and short-lived (1 hour)
    """
    try:
        await auth_service.reset_password(request_data.token, request_data.newPassword)
        return MessageResponse(message="Password has been reset successfully")
    except InvalidTokenError:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid or expired reset token"
        )


@router.post(
    "/change-password",
    response_model=MessageResponse,
    summary="Change password",
    description="Change password for authenticated user",
    tags=["Authentication"]
)
@rate_limit("3/minute")  # Prevent password change abuse
async def change_password(
    request_data: ChangePasswordRequest,
    current_user: CurrentUser,
    auth_service: AuthServiceDep,
    request: Request
) -> MessageResponse:
    """
    Change password for authenticated user.

    Security features:
    - ✅ Rate limiting: 3 requests/minute (enabled)
    - ✅ Authentication required (JWT token)
    - ✅ Current password verification required
    """
    try:
        # Get client IP address for security notification
        client_ip = request.client.host if request.client else None
        await auth_service.change_password(
            user_id=current_user.id,
            current_password=request_data.currentPassword,
            new_password=request_data.newPassword,
            ip_address=client_ip
        )
        return MessageResponse(message="Password changed successfully")
    except InvalidCredentialsError:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Current password is incorrect"
        )
    except UserNotFoundError:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User not found"
        )


@router.get(
    "/me",
    response_model=UserResponse,
    summary="Get current user",
    description="Get currently authenticated user information",
    tags=["Authentication"]
)
async def get_current_user_info(current_user: CurrentUser) -> UserResponse:
    """
    Get current user information.

    Security features:
    - ✅ Authentication required (JWT token via CurrentUser)
    - ⚪ Rate limiting: Not needed (read-only, already auth-protected)
    """
    return UserResponse(**current_user.to_response())


@router.delete(
    "/account",
    response_model=MessageResponse,
    summary="Delete account",
    description="Delete current user's account (soft delete by default)",
    tags=["Authentication"]
)
@rate_limit("1/day")  # Prevent abuse - only allow one deletion per day
async def delete_account(
    request_data: DeleteAccountRequest,
    current_user: CurrentUser,
    auth_service: AuthServiceDep,
    request: Request
) -> MessageResponse:
    """
    Delete current user's account.

    Security features:
    - ✅ Rate limiting: 1 request/day (enabled - CRITICAL)
    - ✅ Authentication required (JWT token)
    - ✅ Password verification (optional but recommended)
    - ✅ Confirmation phrase required
    - ✅ Soft delete by default (GDPR compliant with data anonymization)
    """
    try:
        await auth_service.delete_account(
            user_id=current_user.id,
            password=request_data.password,
            confirmation=request_data.confirmation,
            soft_delete=True
        )
        return MessageResponse(message="Account has been deleted successfully")
    except InvalidCredentialsError as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e)
        )
    except UserNotFoundError:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User not found"
        )
