"""
认证模块 API
============

采用"手机号 + JWT + 单设备登录"的认证方案。

核心接口：
- /login: 手机号验证码登录（签发双 Token + SSE 踢人）
- /refresh: Refresh Token 轮换（换取新 Token 对）
- /logout: 登出（删除设备记录）
- /send-code: 发送短信验证码
- /me: 获取当前用户信息
"""

from __future__ import annotations

from fastapi import APIRouter, Depends, HTTPException, Request, status

from app.api.deps import get_current_user
from app.crud import user as user_crud
from app.db.session import AsyncSession, get_db
from app.models.user import User
from app.schemas.auth import (
    MobileLoginRequest,
    RefreshTokenRequest,
    SendSmsCodeRequest,
    TokenResponse,
)
from app.schemas.common import ApiResponse, success_response
from app.schemas.user import UpdateNicknameRequest, UserProfileResponse
from app.services.auth_service import (
    login_with_sms,
    logout,
    refresh_access_token,
    send_sms_code,
)

router = APIRouter()


@router.post("/send-code", response_model=ApiResponse[dict])
async def send_code(
    request: SendSmsCodeRequest,
    db: AsyncSession = Depends(get_db),
):
    """
    发送短信验证码

    开发阶段验证码直接打印到日志，生产环境接入短信服务商。
    每个手机号每日最多发送 10 次。
    """
    # 校验用户是否存在
    user = await user_crud.get_by_mobile(db, mobile=request.mobile)
    if user is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="用户不存在",
        )

    try:
        await send_sms_code(request.mobile)
    except ValueError as e:
        raise HTTPException(
            status_code=status.HTTP_429_TOO_MANY_REQUESTS,
            detail=str(e),
        )
    return success_response(
        data={"expire_minutes": 5},
        message="验证码已发送",
    )


@router.post("/login", response_model=ApiResponse[TokenResponse])
async def login(
    request: MobileLoginRequest,
    db: AsyncSession = Depends(get_db),
    http_request: Request = None,
):
    """
    手机号验证码登录

    流程：
    1. 校验验证码
    2. 获取或创建用户
    3. 踢掉旧设备（SSE 推送）
    4. 创建/覆盖设备记录
    5. 签发双 Token（Access + Refresh）
    """
    # 获取客户端 IP（优先从 Nginx 转发头读取真实公网 IP）
    client_ip = None
    if http_request:
        xff = http_request.headers.get("x-forwarded-for")
        if xff:
            client_ip = xff.split(",")[0].strip()
        else:
            xri = http_request.headers.get("x-real-ip")
            client_ip = xri or (http_request.client.host if http_request.client else None)

    try:
        result = await login_with_sms(
            db,
            mobile=request.mobile,
            code=request.code,
            device_id=request.device_id,
            device_name=request.device_name,
            os_info=request.os_info,
            app_version=request.app_version,
            ip=client_ip,
        )
    except ValueError as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e),
        )

    return success_response(
        data=TokenResponse(
            access_token=result["access_token"],
            refresh_token=result["refresh_token"],
            user=result["user"],
        ),
        message="登录成功",
    )


@router.post("/refresh", response_model=ApiResponse[dict])
async def refresh_token(
    request: RefreshTokenRequest,
    db: AsyncSession = Depends(get_db),
):
    """
    用 Refresh Token 换取新的 Token 对（Token 轮换）

    每次刷新都会生成全新的 Access Token 和 Refresh Token，
    同时更新设备记录中的 refresh_token_hash。
    """
    try:
        result = await refresh_access_token(db, refresh_token=request.refresh_token)
    except ValueError as e:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=str(e),
            headers={"WWW-Authenticate": "Bearer"},
        )

    return success_response(
        data={
            "access_token": result["access_token"],
            "refresh_token": result["refresh_token"],
        },
        message="Token 刷新成功",
    )


@router.post("/logout", response_model=ApiResponse[dict])
async def do_logout(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """
    用户登出

    删除设备记录，注销 SSE 连接，使当前设备的 Token 失效。
    """
    await logout(db, user_id=current_user.id)

    return success_response(
        data={},
        message="登出成功",
    )


@router.get("/me", response_model=ApiResponse[UserProfileResponse])
async def get_me(
    current_user: User = Depends(get_current_user),
):
    """获取当前登录用户信息"""
    return success_response(
        data=UserProfileResponse(
            id=current_user.id,
            mobile=current_user.mobile,
            nickname=current_user.nickname,
            avatar=current_user.avatar_url or "",
            status=current_user.status,
            source=current_user.source,
            last_login_at=current_user.last_login_at,
            created_at=current_user.created_at,
        )
    )


@router.patch("/me", response_model=ApiResponse[UserProfileResponse])
async def update_me(
    request: UpdateNicknameRequest,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """修改当前用户信息（仅支持修改昵称）"""
    # current_user 来自 get_current_user 的会话，和当前 db 不是同一个会话
    # 需要重新查询到当前会话中才能正确提交
    user = await user_crud.get(db, id=current_user.id)
    if user is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="用户不存在")
    user.nickname = request.nickname.strip()
    await db.commit()
    await db.refresh(user)

    return success_response(
        data=UserProfileResponse(
            id=user.id,
            mobile=user.mobile,
            nickname=user.nickname,
            avatar=user.avatar_url or "",
            status=user.status,
            source=user.source,
            last_login_at=user.last_login_at,
            created_at=user.created_at,
        ),
        message="昵称修改成功",
    )
