"""
Auth API routes: login (rate-limited), refresh, me, logout.
Industry standard: short-lived access token, refresh token, rate limiting on login.
"""
import logging
from datetime import timedelta
from typing import Optional

from fastapi import APIRouter, Depends, HTTPException, Request, status
from fastapi.security import OAuth2PasswordRequestForm

from backend.app.config import (
    ACCESS_TOKEN_EXPIRE_MINUTES,
    LOGIN_RATE_LIMIT_PER_MINUTE,
)
from backend.auth.schemas import Token, UserInfo, RefreshTokenRequest
from backend.auth.dependencies import (
    oauth2_scheme,
    get_current_user,
    require_auth,
)
from backend.auth.rate_limit import check_rate_limit

logger = logging.getLogger("backend.auth")

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


def _get_client_identifier(request: Request, username: str) -> str:
    """Identifier for rate limiting: IP and optionally username."""
    forwarded = request.headers.get("x-forwarded-for")
    ip = (forwarded.split(",")[0].strip()) if forwarded else (request.client.host if request.client else "unknown")
    return f"{ip}:{username}"


@router.post("/login", response_model=Token)
async def login(
    request: Request,
    form_data: OAuth2PasswordRequestForm = Depends(),
):
    """Authenticate and return access + refresh tokens. Rate limited per IP+username."""
    auth_service = getattr(request.app.state, "auth_service", None)
    if not auth_service:
        raise HTTPException(
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
            detail="Authentication service not available",
        )
    identifier = _get_client_identifier(request, form_data.username)
    if not check_rate_limit(identifier, max_per_minute=LOGIN_RATE_LIMIT_PER_MINUTE):
        logger.warning("Login rate limit exceeded for %s", form_data.username)
        raise HTTPException(
            status_code=status.HTTP_429_TOO_MANY_REQUESTS,
            detail="Too many login attempts. Try again later.",
        )
    logger.info("POST /auth/login: attempt username=%s", form_data.username)
    user = auth_service.authenticate_user(form_data.username, form_data.password, include_profile=False)
    if not user:
        logger.info("POST /auth/login: failed username=%s", form_data.username)
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    logger.info("POST /auth/login: success username=%s", form_data.username)
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = auth_service.create_access_token(
        data={"sub": user["username"]},
        expires_delta=access_token_expires,
    )
    refresh_token = auth_service.create_refresh_token(data={"sub": user["username"]})
    return {
        "access_token": access_token,
        "token_type": "bearer",
        "refresh_token": refresh_token,
        "expires_in": ACCESS_TOKEN_EXPIRE_MINUTES * 60,
        "user": user,
    }


@router.post("/refresh", response_model=Token)
async def refresh_token(request: Request, body: RefreshTokenRequest):
    """
    Exchange a valid refresh token for a new access token and new refresh token.
    Send JSON body: {"refresh_token": "..."}.
    """
    auth_service = getattr(request.app.state, "auth_service", None)
    if not auth_service:
        raise HTTPException(
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
            detail="Authentication service not available",
        )
    refresh_token = body.refresh_token
    if not refresh_token:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="refresh_token required",
        )
    payload = auth_service.verify_refresh_token(refresh_token)
    if not payload:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid or expired refresh token",
            headers={"WWW-Authenticate": "Bearer"},
        )
    username = payload.get("sub")
    if not username:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid refresh token")
    user = auth_service.authenticate_user(username, "", include_profile=False)
    if not user:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="User not found")
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    new_access = auth_service.create_access_token(
        data={"sub": username},
        expires_delta=access_token_expires,
    )
    new_refresh = auth_service.create_refresh_token(data={"sub": username})
    return {
        "access_token": new_access,
        "token_type": "bearer",
        "refresh_token": new_refresh,
        "expires_in": ACCESS_TOKEN_EXPIRE_MINUTES * 60,
        "user": user,
    }


@router.get("/me", response_model=UserInfo)
async def get_current_user_info(current_user: UserInfo = Depends(require_auth)):
    """Return current authenticated user."""
    logger.info("GET /auth/me: user=%s", current_user.username)
    return current_user


@router.post("/logout")
async def logout(
    request: Request,
    current_user: UserInfo = Depends(require_auth),
    token: Optional[str] = Depends(oauth2_scheme),
):
    """Invalidate access token and end session."""
    logger.info("POST /auth/logout: username=%s", current_user.username)
    auth_service = getattr(request.app.state, "auth_service", None)
    if auth_service and token:
        auth_service.logout(token)
    return {
        "message": "Logged out successfully",
        "username": current_user.username,
        "session_ended": True,
    }
