"""Authentication routes.

⚠️ AUTO-GENERATED BY PRISM - DO NOT EDIT
Endpoints for signup, login, token refresh, logout, and user info.
"""

from __future__ import annotations

from typing import Annotated

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from {{ project_name }}.auth.password_service import password_service
from {{ project_name }}.auth.token_service import token_service
from {{ project_name }}.database import get_db
from {{ project_name }}.middleware.auth import CurrentActiveUser
from {{ project_name }}.models.{{ user_model_snake }} import {{ user_model }}
from {{ project_name }}.schemas.auth import (
    LoginRequest,
    RefreshTokenRequest,
    SignupRequest,
    TokenResponse,
    UserResponse,
)

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


@router.post("/signup", response_model=TokenResponse, status_code=status.HTTP_201_CREATED)
async def signup(
    data: SignupRequest,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> TokenResponse:
    """Register a new user.

    Args:
        data: Signup data (email/username and password)
        db: Database session

    Returns:
        Access and refresh tokens with user data

    Raises:
        HTTPException: If email/username already exists or password is weak (400)
    """
    # Check if user already exists
    result = await db.execute(
        select({{ user_model }}).where({{ user_model }}.{{ username_field }} == data.{{ username_field }})
    )
    if result.scalar_one_or_none():
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="{{ username_field_title }} already registered",
        )

    # Validate password strength
    is_valid, errors = password_service.validate_password_strength(data.password)
    if not is_valid:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail={"errors": errors},
        )

    # Create user
    user = {{ user_model }}(
        {{ username_field }}=data.{{ username_field }},
        password_hash=password_service.hash_password(data.password),
        is_active=True,
        roles=["{{ default_role }}"],
    )

    db.add(user)
    await db.commit()
    await db.refresh(user)

    # Generate tokens
    access_token = token_service.create_access_token(user.id, user.roles)
    refresh_token = token_service.create_refresh_token(user.id)

    return TokenResponse(
        access_token=access_token,
        refresh_token=refresh_token,
        token_type="bearer",
        user=UserResponse.model_validate(user),
    )


@router.post("/login", response_model=TokenResponse)
async def login(
    data: LoginRequest,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> TokenResponse:
    """Authenticate and return tokens.

    Args:
        data: Login credentials (email/username and password)
        db: Database session

    Returns:
        Access and refresh tokens with user data

    Raises:
        HTTPException: If credentials are incorrect (401) or user is inactive (403)
    """
    # Find user
    result = await db.execute(
        select({{ user_model }}).where({{ user_model }}.{{ username_field }} == data.{{ username_field }})
    )
    user = result.scalar_one_or_none()

    # Verify credentials (constant-time to prevent timing attacks)
    if not user or not password_service.verify_password(data.password, user.password_hash):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect {{ username_field }} or password",
        )

    if not user.is_active:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="User account is inactive",
        )

    # Generate tokens
    access_token = token_service.create_access_token(user.id, user.roles)
    refresh_token = token_service.create_refresh_token(user.id)

    return TokenResponse(
        access_token=access_token,
        refresh_token=refresh_token,
        token_type="bearer",
        user=UserResponse.model_validate(user),
    )


@router.post("/refresh", response_model=TokenResponse)
async def refresh_token(
    data: RefreshTokenRequest,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> TokenResponse:
    """Refresh access token using refresh token.

    Args:
        data: Refresh token
        db: Database session

    Returns:
        New access token (same refresh token)

    Raises:
        HTTPException: If refresh token is invalid or user not found (401)
    """
    try:
        payload = token_service.verify_token(data.refresh_token, token_type="refresh")
        user_id = int(payload.get("sub"))
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid refresh token",
        )

    # Fetch user
    result = await db.execute(select({{ user_model }}).where({{ user_model }}.id == user_id))
    user = result.scalar_one_or_none()

    if not user or not user.is_active:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="User not found or inactive",
        )

    # Generate new access token
    access_token = token_service.create_access_token(user.id, user.roles)

    return TokenResponse(
        access_token=access_token,
        refresh_token=data.refresh_token,  # Return same refresh token
        token_type="bearer",
        user=UserResponse.model_validate(user),
    )


@router.post("/logout")
async def logout() -> dict[str, str]:
    """Logout user.

    For stateless JWT, logout is client-side (discard tokens).
    For token blacklist implementation, add token to blacklist here.

    Returns:
        Success message
    """
    return {"message": "Logged out successfully"}


@router.get("/me", response_model=UserResponse)
async def get_current_user_info(
    current_user: CurrentActiveUser,
) -> UserResponse:
    """Get current authenticated user information.

    Args:
        current_user: Authenticated user from middleware

    Returns:
        User data (excluding password_hash)
    """
    return UserResponse.model_validate(current_user)
