"""邮箱/手机验证码验证 API"""

import random
import uuid as _uuid
from datetime import datetime, timedelta

from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel, EmailStr
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.compat import UTC
from app.core.cache import cache
from app.core.permissions import get_current_user
from app.db import get_db
from app.models.user import User

router = APIRouter()
VERIFY_PREFIX = "verify_code:"


def uid(u: dict) -> _uuid.UUID:
    return _uuid.UUID(u["sub"])


def _generate_code() -> str:
    return str(random.randint(100000, 999999))


class SendEmailCodeRequest(BaseModel):
    email: EmailStr


class VerifyEmailCodeRequest(BaseModel):
    code: str


class SendPhoneCodeRequest(BaseModel):
    phone: str


class VerifyPhoneCodeRequest(BaseModel):
    code: str


@router.post("/verification/send-email", summary="发送邮箱验证码")
async def send_email_code(
    req: SendEmailCodeRequest,
    user: dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    u = (await db.execute(select(User).where(User.id == uid(user)))).scalar()
    if not u:
        raise HTTPException(404)
    if u.email != req.email:
        raise HTTPException(400, "验证邮箱必须与注册邮箱一致")

    # 限速检查：60 秒内不可重复发送
    existing = await cache.get(f"{VERIFY_PREFIX}email:{uid(user)}")
    if existing:
        raise HTTPException(429, "请 60 秒后再试")

    code = _generate_code()
    await cache.set(
        f"{VERIFY_PREFIX}email:{uid(user)}",
        {"code": code, "email": req.email, "created_at": datetime.now(UTC).isoformat()},
        ttl=600,
    )

    # 发送邮件
    from app.services.email_service import send_email
    from app.services.email_templates import render_template
    html = render_template(
        "verification_code",
        user_name=u.display_name,
        code=code,
        minutes=10,
    )
    await send_email(req.email, "邮箱验证 - 肿瘤科文献中心", html)
    return {"status": "sent"}


@router.post("/verification/verify-email", summary="验证邮箱")
async def verify_email_code(
    req: VerifyEmailCodeRequest,
    user: dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    stored = await cache.pop(f"{VERIFY_PREFIX}email:{uid(user)}")
    if not stored:
        raise HTTPException(400, "验证码已过期或未发送")

    if stored.get("code") != req.code:
        raise HTTPException(400, "验证码错误")

    u = (await db.execute(select(User).where(User.id == uid(user)))).scalar()
    if not u:
        raise HTTPException(404)
    u.email_verified = True
    await db.commit()
    return {"status": "verified"}


@router.post("/verification/send-phone", summary="发送手机验证码")
async def send_phone_code(
    req: SendPhoneCodeRequest,
    user: dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    u = (await db.execute(select(User).where(User.id == uid(user)))).scalar()
    if not u:
        raise HTTPException(404)

    # 限速检查
    existing = await cache.get(f"{VERIFY_PREFIX}phone:{uid(user)}")
    if existing:
        raise HTTPException(429, "请 60 秒后再试")

    code = _generate_code()
    await cache.set(
        f"{VERIFY_PREFIX}phone:{uid(user)}",
        {"code": code, "phone": req.phone, "created_at": datetime.now(UTC).isoformat()},
        ttl=600,
    )

    # 更新手机号
    u.phone = req.phone
    await db.commit()

    from app.services.sms_service import send_sms
    await send_sms(req.phone, code)
    return {"status": "sent"}


@router.post("/verification/verify-phone", summary="验证手机")
async def verify_phone_code(
    req: VerifyPhoneCodeRequest,
    user: dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    stored = await cache.pop(f"{VERIFY_PREFIX}phone:{uid(user)}")
    if not stored:
        raise HTTPException(400, "验证码已过期或未发送")

    if stored.get("code") != req.code:
        raise HTTPException(400, "验证码错误")

    u = (await db.execute(select(User).where(User.id == uid(user)))).scalar()
    if not u:
        raise HTTPException(404)
    u.phone_verified = True
    await db.commit()
    return {"status": "verified"}
