"""
Authentication endpoints.

Handles user login, token refresh, logout, and retrieving current user profile.
"""

from fastapi import APIRouter, Depends, Request, Response, status
from fastapi.security import HTTPAuthorizationCredentials
from sqlalchemy.ext.asyncio import AsyncSession

from app.config import settings
from app.core.auth_deps import get_current_active_user, http_bearer
from app.core.dependencies import get_db
from app.core.permissions import resolve_user_permissions
from app.core.rate_limit import limiter
from app.core.responses import SuccessResponse
from app.models.user import User
from app.schemas.auth import (
    BootstrapRequest,
    BootstrapResponse,
    ForgotPasswordRequest,
    ForgotPasswordResponse,
    LoginRequest,
    MessageResponse,
    RefreshRequest,
    ResetPasswordRequest,
    TokenResponse,
    UserMeResponse,
)
from app.services.auth_service import AuthService

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


@router.post(
    "/bootstrap",
    response_model=SuccessResponse[BootstrapResponse],
    status_code=status.HTTP_201_CREATED,
    summary="Bootstrap initial superadmin",
    description=(
        "Initialize the first lab branch and superadmin user. "
        "Can only be executed once when the system has no users."
    ),
)
async def bootstrap(
    payload: BootstrapRequest,
    db: AsyncSession = Depends(get_db),
) -> SuccessResponse[BootstrapResponse]:
    result = await _auth_service.bootstrap(db, payload)
    return SuccessResponse(data=result)


@router.post(
    "/login",
    response_model=SuccessResponse[TokenResponse],
    status_code=status.HTTP_200_OK,
    summary="Log in user",
    description="Authenticate user with phone and password, returns access and refresh JWTs.",
)
@limiter.limit("5/minute")
async def login(
    request: Request,
    response: Response,
    payload: LoginRequest,
    db: AsyncSession = Depends(get_db),
) -> SuccessResponse[TokenResponse]:
    token_response = await _auth_service.login(db, payload)
    response.set_cookie(
        key="access_token",
        value=token_response.access_token,
        httponly=True,
        samesite="lax",
        secure=settings.is_production,
        max_age=settings.JWT_ACCESS_TOKEN_EXPIRE_MINUTES * 60,
        path="/",
    )
    if token_response.refresh_token:
        response.set_cookie(
            key="refresh_token",
            value=token_response.refresh_token,
            httponly=True,
            samesite="lax",
            secure=settings.is_production,
            max_age=settings.JWT_REFRESH_TOKEN_EXPIRE_DAYS * 86400,
            path="/",
        )
    return SuccessResponse(data=token_response)


@router.post(
    "/refresh",
    response_model=SuccessResponse[TokenResponse],
    status_code=status.HTTP_200_OK,
    summary="Refresh access token",
    description="Issue a new access token and rotate refresh token using a valid refresh token.",
)
async def refresh(
    request: Request,
    response: Response,
    payload: RefreshRequest,
    db: AsyncSession = Depends(get_db),
) -> SuccessResponse[TokenResponse]:
    if not payload.refresh_token and "refresh_token" in request.cookies:
        payload = RefreshRequest(refresh_token=request.cookies["refresh_token"])
    token_response = await _auth_service.refresh(db, payload)
    response.set_cookie(
        key="access_token",
        value=token_response.access_token,
        httponly=True,
        samesite="lax",
        secure=settings.is_production,
        max_age=settings.JWT_ACCESS_TOKEN_EXPIRE_MINUTES * 60,
        path="/",
    )
    if token_response.refresh_token:
        response.set_cookie(
            key="refresh_token",
            value=token_response.refresh_token,
            httponly=True,
            samesite="lax",
            secure=settings.is_production,
            max_age=settings.JWT_REFRESH_TOKEN_EXPIRE_DAYS * 86400,
            path="/",
        )
    return SuccessResponse(data=token_response)


@router.post(
    "/logout",
    response_model=SuccessResponse[dict[str, str]],
    status_code=status.HTTP_200_OK,
    summary="Log out user",
    description="Revoke the active access token and refresh token session in PostgreSQL.",
)
async def logout(
    request: Request,
    response: Response,
    credentials: HTTPAuthorizationCredentials | None = Depends(http_bearer),
    current_user: User = Depends(get_current_active_user),
) -> SuccessResponse[dict[str, str]]:
    token = (
        credentials.credentials
        if credentials and credentials.credentials
        else request.cookies.get("access_token")
    )
    await _auth_service.logout(current_user.id, token=token)
    response.delete_cookie(key="access_token", path="/")
    response.delete_cookie(key="refresh_token", path="/")
    return SuccessResponse(data={"message": "Logged out successfully."})


@router.get(
    "/me",
    response_model=SuccessResponse[UserMeResponse],
    status_code=status.HTTP_200_OK,
    summary="Get current user profile",
    description="Retrieve the profile of the currently authenticated user.",
)
async def get_me(
    current_user: User = Depends(get_current_active_user),
    db: AsyncSession = Depends(get_db),
) -> SuccessResponse[UserMeResponse]:
    perms = sorted(await resolve_user_permissions(db, current_user))
    user_me = UserMeResponse(
        id=current_user.id,
        name=current_user.name,
        phone=current_user.phone,
        email=current_user.email,
        role=str(current_user.role.value if hasattr(current_user.role, "value") else current_user.role),
        lab_id=current_user.lab_id,
        is_active=current_user.is_active,
        license_no=current_user.license_no,
        permissions=perms,
    )
    return SuccessResponse(data=user_me)


@router.post(
    "/forgot-password",
    response_model=SuccessResponse[ForgotPasswordResponse],
    status_code=status.HTTP_200_OK,
    summary="Request password reset OTP",
    description=(
        "Dispatches a 6-digit verification code to the registered staff email "
        "when the account exists and is active."
    ),
)
@limiter.limit("5/minute")
async def forgot_password(
    request: Request,
    payload: ForgotPasswordRequest,
    db: AsyncSession = Depends(get_db),
) -> SuccessResponse[ForgotPasswordResponse]:
    result = await _auth_service.forgot_password(db, payload)
    return SuccessResponse(data=result)


@router.post(
    "/reset-password",
    response_model=SuccessResponse[MessageResponse],
    status_code=status.HTTP_200_OK,
    summary="Reset password with OTP",
    description="Verifies the 6-digit OTP passcode and updates the user's password.",
)
@limiter.limit("5/minute")
async def reset_password(
    request: Request,
    payload: ResetPasswordRequest,
    db: AsyncSession = Depends(get_db),
) -> SuccessResponse[MessageResponse]:
    result = await _auth_service.reset_password(db, payload)
    return SuccessResponse(data=result)
