"""
Authentication routes for user registration, login, and logout.
Provides JWT-based authentication endpoints including password reset.
"""
from fastapi import APIRouter, Depends, HTTPException, status
from pydantic import BaseModel, EmailStr
from app.models import User, UserCreate, UserRead, UserUpdate
from app.users import fastapi_users, current_active_user, auth_backend, get_user_manager
from fastapi_users import exceptions

router = APIRouter(prefix="/auth", tags=["auth"])


# Include FastAPI Users routers
router.include_router(
    fastapi_users.get_register_router(UserRead, UserCreate),
    prefix="/jwt",
    tags=["auth"],
)
router.include_router(
    fastapi_users.get_auth_router(auth_backend),
    prefix="/jwt",
    tags=["auth"],
)


# Password reset schemas
class ForgotPasswordRequest(BaseModel):
    email: EmailStr


class ResetPasswordRequest(BaseModel):
    token: str
    password: str


# Custom password reset endpoints for on-premise deployment
# (shows reset token directly instead of sending email)
@router.post("/forgot-password", tags=["auth"])
async def forgot_password(
    request: ForgotPasswordRequest,
    user_manager = Depends(get_user_manager),
):
    """
    Request password reset for on-premise deployment.
    Returns reset token directly (no email sent).
    """
    try:
        # Get user by email
        user = await user_manager.get_by_email(request.email)

        if user is None:
            # Don't reveal if user exists or not for security
            return {"message": "If the email exists, a reset token has been generated"}

        # Generate reset token
        token_data = {
            "user_id": user.id,
            "email": user.email,
        }
        reset_token = await user_manager.generate_token(token_data)

        # For on-premise deployment, return token directly
        # In production with email, you would send this via email instead
        return {
            "message": "Password reset token generated",
            "reset_token": reset_token,
        }

    except exceptions.UserNotExists:
        # Don't reveal if user exists or not
        return {"message": "If the email exists, a reset token has been generated"}


@router.post("/reset-password", tags=["auth"])
async def reset_password(
    request: ResetPasswordRequest,
    user_manager = Depends(get_user_manager),
):
    """
    Reset password using token.
    """
    try:
        # Verify token and get user data
        token_data = await user_manager.verify_token(request.token)

        if not token_data:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Invalid or expired reset token"
            )

        # Get user
        user = await user_manager.get_by_email(token_data["email"])

        if user is None:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="User not found"
            )

        # Update password
        await user_manager.update(
            user_update=UserUpdate(password=request.password),
            user=user,
        )

        return {"message": "Password reset successfully"}

    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid or expired reset token"
        )


@router.get("/me", response_model=UserRead, tags=["auth"])
async def get_current_user_profile(user: User = Depends(current_active_user)) -> UserRead:
    """
    Get current authenticated user's profile.
    
    Returns the profile of the currently authenticated user.
    Requires valid JWT token in Authorization header.
    """
    return UserRead(
        id=user.id,
        email=user.email,
        name=user.name,
        is_active=user.is_active,
        is_verified=user.is_verified,
        created_at=user.created_at,
    )


@router.post("/logout", tags=["auth"])
async def logout(user: User = Depends(current_active_user)):
    """
    Logout current user.
    
    For JWT-based authentication, this is a client-side operation
    (client should discard the token). This endpoint exists for consistency
    and can be used to invalidate tokens server-side if needed in the future.
    """
    return {"message": "Successfully logged out"}
