import json
import logging
from datetime import datetime
from typing import Annotated, Any

from fastapi import APIRouter, HTTPException
from fastapi.params import Depends
from pydantic import BaseModel
from sqlalchemy.exc import NoResultFound
from sqlmodel import Session, select

from nyahome.config import config_manager
from nyahome.database import ModelUser, get_session
from nyahome.service.secure_service import SecureChange, s_append_secure_changes
from nyahome.service.verify_service import s_send_test_email, s_send_verify_email, s_verify_email

from .auth import create_access_token, save_password, verify_password, verify_token
from .response_model import ReturnDto

logger = logging.getLogger(__name__)

admin_router = APIRouter(tags=["Admin"], prefix="/admin")


class UserLogin(BaseModel):
    username: str
    password: str


class UserInfo(BaseModel):
    name: str
    display_name: str
    avatar_url: str
    background_url: str
    description: str


class ChangePassword(BaseModel):
    old_password: str
    new_password: str


class SendEmail(BaseModel):
    to: str


class VerifyEmail(BaseModel):
    to: str
    verify_code: str


@admin_router.post("/login/name/", name="用户登录")
async def nyahome_login_name(user: UserLogin, session: Annotated[Session, Depends(get_session)]) -> ReturnDto:
    """
    使用用户名密码登录。

    Raises:
        HTTPException: 404 表示尝试登录的用户不存在。

    Returns:
        ReturnDto，其中 result 字段包含 `user_id` 和 `access_token` 两个字段。
    """
    try:
        u: ModelUser = session.exec(select(ModelUser).where(ModelUser.name == user.username)).one()
    except NoResultFound:
        raise HTTPException(status_code=404, detail="用户不存在") from None

    if verify_password(user.password, u.password):
        change = SecureChange(
            created_at=datetime.now(),
            type="login",
            old=None,
            new=None,
        )
        u.secure_changes = s_append_secure_changes(u.secure_changes, change)
        session.add(u)
        session.commit()
        return ReturnDto(
            result={
                "user_id": u.id,
                "access_token": create_access_token(u.id, u.password, 30),
            }
        )
    raise HTTPException(status_code=401, detail="验证失败，请检查用户名和密码是否正确")


@admin_router.get("/me/", name="获取登录用户信息")
async def nyahome_get_me(user: Annotated[ModelUser, Depends(verify_token)]) -> ModelUser:
    """
    获取当前登录的用户的详细信息。

    Returns:
        ModelUser
    """
    return user


@admin_router.post("/me/", name="修改登录用户信息")
async def nyahome_post_me(
    info: UserInfo, user: Annotated[ModelUser, Depends(verify_token)], session: Annotated[Session, Depends(get_session)]
) -> ModelUser:
    """
    修改当前登录的用户的详细信息。
    此端点可以修改除了用户密码、邮箱、手机号之外的大部分用户信息。

    Returns:
        ModelUser
    """
    user.name = info.name
    user.display_name = info.display_name
    user.avatar_url = info.avatar_url
    user.background_url = info.background_url
    user.description = info.description
    session.add(user)
    session.commit()
    session.refresh(user)
    return user


@admin_router.post("/me/password/", name="修改用户密码")
async def nyahome_change_password(
    change: ChangePassword,
    user: Annotated[ModelUser, Depends(verify_token)],
    session: Annotated[Session, Depends(get_session)],
) -> ReturnDto:
    """
    修改用户密码。

    Raises:
        HTTPException: 400 提供的旧密码错误。

    Returns:
        不重要的 ReturnDto，无异常本身即表示修改成功。
    """
    if verify_password(change.old_password, user.password):
        user.password = save_password(change.new_password)
        change_ = SecureChange(
            created_at=datetime.now(),
            type="change_password",
            old=None,
            new=None,
        )
        user.secure_changes = s_append_secure_changes(user.secure_changes, change_)
        session.add(user)
        session.commit()
        return ReturnDto(success=True)
    raise HTTPException(status_code=400, detail="修改密码需要提供旧的密码，但提供的旧密码错误。") from None


@admin_router.post("/me/email-verify/", name="验证并修改用户邮箱")
async def nyahome_verify_email(
    to: VerifyEmail,
    user: Annotated[ModelUser, Depends(verify_token)],
    session: Annotated[Session, Depends(get_session)],
) -> ReturnDto:
    """
    验证用户提供的邮箱以及验证码。
    需要先通过 `/me/email-verify/send/` 发送验证码。验证码有五分钟有效期，为六位数字，需以字符串形式提供。

    Returns:
        ReturnDto，其中 success 字段表明是否成功。如果成功，则用户邮箱已被修改。
        不返回完整的 ModelUser，WebUI 自行负责前端用户信息更新。
    """
    success = await s_verify_email(user_id=user.id, address=to.to, verify_code=to.verify_code)
    if success:
        old_email = user.email
        user.email = to.to
        user.secure_changes = s_append_secure_changes(
            user.secure_changes,
            SecureChange(
                created_at=datetime.now(),
                type="change_email",
                old=old_email,
                new=to.to,
            ),
        )
        session.add(user)
        session.commit()
        logger.info(f"已更新用户 {user.id} 的邮件地址至 {user.email}")
    return ReturnDto(success=success)


@admin_router.post("/me/email-verify/send/", name="发送修改邮箱验证码")
async def nyahome_verify_email_send(to: SendEmail, user: Annotated[ModelUser, Depends(verify_token)]) -> ReturnDto:
    """
    请求对新的邮箱发送验证码。验证码有五分钟有效期，为六位数字。

    Returns:
        ReturnDto，其中 success 字段表明是否成功。
    """
    success = await s_send_verify_email(user.id, to.to)
    return ReturnDto(success=success)


@admin_router.get("/me/secure_changes/", name="获取用户安全变更记录")
async def nyahome_get_secure_changes(
    user: Annotated[ModelUser, Depends(verify_token)],
) -> list[SecureChange]:
    """
    获取用户的安全变更记录。
    安全变更记录包括：登录、修改密码、修改邮箱、修改手机号。

    Returns:
        SecureChange 列表。
    """
    return json.loads(user.secure_changes)  # type: ignore[no-any-return]


@admin_router.get("/site_config/", name="获取 NyaHome 设置")
async def get_site_config(user: Annotated[ModelUser, Depends(verify_token)]) -> dict[str, Any]:
    """
    获取 NyaHome 的设置。
    需要管理员权限才能访问。

    Raises:
        HTTPException: 403 表示请求用户非管理员。

    Returns:
        dict[str, Any] NyaHome 设置
    """
    if not user.is_admin:
        raise HTTPException(status_code=403, detail="非管理员禁止访问") from None
    return config_manager.get_config()


@admin_router.post("/site_config/", name="修改 NyaHome 设置")
async def set_site_config(
    user: Annotated[ModelUser, Depends(verify_token)],
    config_: dict[str, Any],
) -> dict[str, Any]:
    """
    设置 NyaHome 的设置。
    需要管理员权限才能访问。

    Raises:
        HTTPException: 403 表示请求用户非管理员。

    Returns:
        dict[str, Any] 更新过的 NyaHome 设置
    """
    if not user.is_admin:
        raise HTTPException(status_code=403, detail="非管理员禁止访问") from None
    final_config = config_manager.set_config(config_)
    await config_manager.async_save_config()
    return final_config


@admin_router.post("/email-test/", name="测试邮件发送")
async def nyahome_test_email(to: SendEmail, user: Annotated[ModelUser, Depends(verify_token)]) -> ReturnDto:
    """
    NyaHome 管理员面板中的测试邮件端点。

    Args:
        to: 测试邮件发送目标
        user: 当前用户，需要为管理员

    Raises:
        HTTPException: 403 表示请求用户非管理员。

    Returns:
        ReturnDto
    """
    if not user.is_admin:
        raise HTTPException(status_code=403, detail="非管理员禁止访问") from None
    success = await s_send_test_email(to.to)
    logger.info(f"发送测试邮件到 {to} - {success=}")
    return ReturnDto(success=success)
