"""
인증 API 라우터

카카오 로그인, 토큰 갱신, 로그아웃, 내 정보 조회 엔드포인트를 제공합니다.
"""

from typing import Optional

from fastapi import APIRouter, Depends, Header, Request, status
from fastapi.responses import Response
from sqlalchemy.ext.asyncio import AsyncSession

from app.database.session import get_session
from app.user.dependencies import get_current_user
from app.user.models import User
from app.user.schemas.user_schema import (
    AccessTokenResponse,
    KakaoCallbackRequest,
    KakaoLoginResponse,
    LoginResponse,
    RefreshTokenRequest,
    UserResponse,
)
from app.user.services import auth_service, kakao_client

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


@router.get(
    "/kakao/login",
    response_model=KakaoLoginResponse,
    summary="카카오 로그인 URL 요청",
    description="카카오 OAuth 인증 페이지 URL을 반환합니다.",
)
async def kakao_login() -> KakaoLoginResponse:
    """
    카카오 로그인 URL 반환

    프론트엔드에서 이 URL로 사용자를 리다이렉트하면
    카카오 로그인 페이지가 표시됩니다.
    """
    auth_url = kakao_client.get_authorization_url()
    return KakaoLoginResponse(auth_url=auth_url)


@router.post(
    "/kakao/callback",
    response_model=LoginResponse,
    summary="카카오 로그인 콜백",
    description="카카오 인가 코드를 받아 로그인/가입을 처리하고 JWT 토큰을 발급합니다.",
)
async def kakao_callback(
    request: Request,
    body: KakaoCallbackRequest,
    session: AsyncSession = Depends(get_session),
    user_agent: Optional[str] = Header(None, alias="User-Agent"),
) -> LoginResponse:
    """
    카카오 로그인 콜백

    카카오 로그인 성공 후 발급받은 인가 코드로
    JWT 토큰을 발급합니다.

    신규 사용자인 경우 자동으로 회원가입이 처리됩니다.
    """
    # 클라이언트 IP 추출
    ip_address = request.client.host if request.client else None

    # X-Forwarded-For 헤더 확인 (프록시/로드밸런서 뒤에 있는 경우)
    forwarded_for = request.headers.get("X-Forwarded-For")
    if forwarded_for:
        ip_address = forwarded_for.split(",")[0].strip()

    return await auth_service.kakao_login(
        code=body.code,
        session=session,
        user_agent=user_agent,
        ip_address=ip_address,
    )


@router.post(
    "/refresh",
    response_model=AccessTokenResponse,
    summary="토큰 갱신",
    description="리프레시 토큰으로 새 액세스 토큰을 발급합니다.",
)
async def refresh_token(
    body: RefreshTokenRequest,
    session: AsyncSession = Depends(get_session),
) -> AccessTokenResponse:
    """
    액세스 토큰 갱신

    유효한 리프레시 토큰을 제출하면 새 액세스 토큰을 발급합니다.
    리프레시 토큰은 변경되지 않습니다.
    """
    return await auth_service.refresh_tokens(
        refresh_token=body.refresh_token,
        session=session,
    )


@router.post(
    "/logout",
    status_code=status.HTTP_204_NO_CONTENT,
    summary="로그아웃",
    description="현재 세션의 리프레시 토큰을 폐기합니다.",
)
async def logout(
    body: RefreshTokenRequest,
    current_user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_session),
) -> Response:
    """
    로그아웃

    현재 사용 중인 리프레시 토큰을 폐기합니다.
    해당 토큰으로는 더 이상 액세스 토큰을 갱신할 수 없습니다.
    """
    await auth_service.logout(
        user_id=current_user.id,
        refresh_token=body.refresh_token,
        session=session,
    )
    return Response(status_code=status.HTTP_204_NO_CONTENT)


@router.post(
    "/logout/all",
    status_code=status.HTTP_204_NO_CONTENT,
    summary="모든 기기에서 로그아웃",
    description="사용자의 모든 리프레시 토큰을 폐기합니다.",
)
async def logout_all(
    current_user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_session),
) -> Response:
    """
    모든 기기에서 로그아웃

    사용자의 모든 리프레시 토큰을 폐기합니다.
    모든 기기에서 재로그인이 필요합니다.
    """
    await auth_service.logout_all(
        user_id=current_user.id,
        session=session,
    )
    return Response(status_code=status.HTTP_204_NO_CONTENT)


@router.get(
    "/me",
    response_model=UserResponse,
    summary="내 정보 조회",
    description="현재 로그인한 사용자의 정보를 반환합니다.",
)
async def get_me(
    current_user: User = Depends(get_current_user),
) -> UserResponse:
    """
    내 정보 조회

    현재 로그인한 사용자의 상세 정보를 반환합니다.
    """
    return UserResponse.model_validate(current_user)
