"""用户资料 endpoint。

路由前缀 `/api/v1/user`,全部需 Bearer 鉴权(用户级数据,不同于 MVP 透传接口):
  PATCH  /profile   修改昵称
  POST   /avatar    上传头像(multipart,字段名 file)
  DELETE /          注销账号(软删除 + 匿名化)

昵称/头像后端持久化到 user 表,登录后经 /auth/me 与登录响应回传客户端——这才是
"改完重登仍生效"的唯一数据源(此前客户端只存本地、退登即丢)。
"""
from __future__ import annotations

import logging

from fastapi import APIRouter, File, HTTPException, Query, UploadFile

from app.api.deps import CurrentUser, DbSession
from app.core import media
from app.repositories import onboarding as onboarding_repo
from app.repositories import user as user_repo
from app.repositories import wallet as wallet_repo
from app.schemas.auth import UserOut
from app.schemas.user import (
    OkResponse,
    OnboardingCompleteRequest,
    OnboardingStatusResponse,
    ProfileUpdateRequest,
)

logger = logging.getLogger("shagua.user")

router = APIRouter(prefix="/api/v1/user", tags=["user"])


@router.patch("/profile", response_model=UserOut, summary="修改昵称")
def update_profile(req: ProfileUpdateRequest, user: CurrentUser, db: DbSession) -> UserOut:
    updated = user_repo.update_nickname(db, user, nickname=req.nickname)
    logger.info("update nickname user_id=%d", user.id)
    return UserOut.model_validate(updated)


@router.post("/avatar", response_model=UserOut, summary="上传头像")
async def upload_avatar(
    user: CurrentUser,
    db: DbSession,
    file: UploadFile = File(..., description="头像图片(jpeg/png/webp,≤5MB)"),
) -> UserOut:
    data = await file.read()
    try:
        url = media.save_avatar(user.id, data)
    except media.MediaError as e:
        raise HTTPException(status_code=400, detail=str(e)) from e

    old_url = user.avatar_url
    updated = user_repo.set_avatar_url(db, user, avatar_url=url)
    media.delete_avatar(old_url)  # 落库成功后再删旧文件,避免删了新的没存上
    logger.info("update avatar user_id=%d url=%s", user.id, url)
    return UserOut.model_validate(updated)


@router.post("/onboarding/complete", response_model=OkResponse, summary="标记新手引导完成(按 设备+账号)")
def complete_onboarding(
    req: OnboardingCompleteRequest, user: CurrentUser, db: DbSession
) -> OkResponse:
    """走完新手引导时调一次。按 (当前账号, device_id) 落一条完成标记,跨卸载重装持久。
    幂等:重复调用不报错。device_id 取客户端硬件级 ANDROID_ID,与登录请求一致。"""
    onboarding_repo.mark_completed(db, user_id=user.id, device_id=req.device_id)
    logger.info("onboarding complete user_id=%d device_len=%d", user.id, len(req.device_id))
    return OkResponse()


@router.post("/onboarding/reset", response_model=OkResponse, summary="重置新手引导(删该 设备+账号 完成标记,下次登录重走)")
def reset_onboarding(
    req: OnboardingCompleteRequest, user: CurrentUser, db: DbSession
) -> OkResponse:
    """删该 (当前账号, device_id) 的引导完成标记 → 下次登录 onboarding_completed=false,客户端重走。
    与 /onboarding/complete 互逆。device_id 取客户端硬件级 ANDROID_ID(与登录/complete 一致)。
    幂等:无记录也返回 ok。仅删自己(当前 JWT 用户)这台设备的记录,不影响别的账号/设备。"""
    deleted = onboarding_repo.delete_completion(db, user_id=user.id, device_id=req.device_id)
    logger.info("onboarding reset user_id=%d device_len=%d deleted=%d", user.id, len(req.device_id), deleted)
    return OkResponse()


@router.get(
    "/onboarding/status",
    response_model=OnboardingStatusResponse,
    summary="查新手引导是否已完成(按 设备+账号)",
)
def onboarding_status(
    user: CurrentUser,
    db: DbSession,
    device_id: str = Query("", max_length=64, description="硬件级 ANDROID_ID;空=按未完成处理"),
) -> OnboardingStatusResponse:
    """已登录用户启动时查:该 (账号, 设备) 走过引导没。false → 客户端重走(运营在 admin 删了该设备
    记录即触发)。替代原 force_onboarding(按用户)——改设备维度后这是"运营触发重走"的查询入口。
    device_id 为空一律按未完成(同登录:不误跳过)。"""
    completed = onboarding_repo.is_completed(db, user_id=user.id, device_id=device_id)
    return OnboardingStatusResponse(completed=completed)


@router.delete("", response_model=OkResponse, summary="注销账号(软删除)")
def delete_account(user: CurrentUser, db: DbSession) -> OkResponse:
    # 资金前置校验:注销是软删 + 匿名化,余额一旦留在 deleted 行就锁死(既退不出、新号也
    # 拿不回)。有可提现现金 / 在审提现单 → 拒绝注销,引导用户先把钱处理掉。
    # (pending 提现转账已在途、对账 worker 不依赖 user.status 照常到账,故不拦 pending。)
    if wallet_repo.get_cash_balance_cents(db, user.id) > 0:
        raise HTTPException(
            status_code=409, detail="账户还有未提现的现金余额,请先提现后再注销"
        )
    if wallet_repo.has_reviewing_withdraw(db, user.id):
        raise HTTPException(
            status_code=409, detail="有提现正在审核中,请等审核完成后再注销"
        )
    media.delete_avatar(user.avatar_url)
    user_repo.soft_delete_account(db, user)
    logger.info("delete account user_id=%d", user.id)
    return OkResponse()
