from typing import Annotated

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

from nyahome.database import (
    AiiModel,
    AiiModelPublic,
    AiiProvider,
    AiiProviderPublic,
    ModelUser,
    get_session,
    z_aii_model,
    z_aii_provider,
)
from nyahome.service.aii_service import apply_get_models, s_check_remote_model, s_list_remote_provider_models

from .auth import verify_token
from .response_model import ReturnDto

aii_router = APIRouter(tags=["Aii"], prefix="/aii")


@aii_router.get("/model/")
async def get_all_model(session: Annotated[Session, Depends(get_session)]) -> ReturnDto:
    final_model_list = apply_get_models(session)
    return ReturnDto(result=final_model_list)


@aii_router.post("/model/")
async def add_model(
    model: AiiModelPublic,
    user: Annotated[ModelUser, Depends(verify_token)],
    session: Annotated[Session, Depends(get_session)],
) -> ReturnDto:
    if not user.is_admin:
        raise HTTPException(status_code=401, detail="用户无权限管理模型。") from None

    try:
        ap: AiiProvider = session.exec(select(AiiProvider).where(AiiProvider.id == model.aii_provider_id)).one()
    except NoResultFound:
        raise HTTPException(status_code=404, detail="Provider 不存在。") from None
    am = AiiModel(
        model_name=model.model_name,
        max_context_length=model.max_context_length,
        aii_provider_id=model.aii_provider_id,
        aii_provider=ap,
    )
    session.add(am)
    session.commit()
    session.refresh(am)
    return ReturnDto(result=z_aii_model(am))


@aii_router.get("/provider/")
async def get_all_provider(session: Annotated[Session, Depends(get_session)]) -> ReturnDto:
    aii_providers = session.exec(select(AiiProvider)).all()
    return ReturnDto(result=[z_aii_provider(ap) for ap in aii_providers])


@aii_router.post("/provider/")
async def add_provider(
    provider: AiiProviderPublic,
    user: Annotated[ModelUser, Depends(verify_token)],
    session: Annotated[Session, Depends(get_session)],
) -> ReturnDto:
    if not user.is_admin:
        raise HTTPException(status_code=401, detail="用户无权限管理模型。") from None
    ap = AiiProvider(name=provider.name, base_url=provider.base_url, api_key=provider.api_key)
    session.add(ap)
    session.commit()
    session.refresh(ap)
    return ReturnDto(result=z_aii_provider(ap))


@aii_router.get("/provider/{id_}/remote/models/")
async def get_provider_remote_models(
    id_: int, user: Annotated[ModelUser, Depends(verify_token)], session: Annotated[Session, Depends(get_session)]
) -> ReturnDto:
    if not user.is_admin:
        raise HTTPException(status_code=401, detail="用户无权限管理模型。") from None
    try:
        ap: AiiProvider = session.exec(select(AiiProvider).where(AiiProvider.id == id_)).one()
    except NoResultFound:
        raise HTTPException(status_code=404, detail="Provider 不存在。") from None
    models = await s_list_remote_provider_models(ap.base_url, ap.api_key)
    # 只返回模型名称列表，方便前端填入表单
    return ReturnDto(result=[m["id"] for m in models])


@aii_router.get("/provider/{id_}/remote/model/{model_name}/")
async def check_remote_provider_model(
    id_: int, model_name: str, session: Annotated[Session, Depends(get_session)]
) -> ReturnDto:
    """
    检测指定提供商的指定名称模型是否可用。
    Args:
        id_: 模型提供商 ID。
        model_name: 模型名称。
        session: 数据库连接对象。

    Raises:
        HTTPException: 404 表明提供商 ID 未找到。

    Returns:
        ReturnDto，其中 result 字段为布尔值，表明指定名称模型的可用状态。
    """
    try:
        ap: AiiProvider = session.exec(select(AiiProvider).where(AiiProvider.id == id_)).one()
    except NoResultFound:
        raise HTTPException(status_code=404, detail="Provider 不存在。") from None
    return ReturnDto(result=await s_check_remote_model(model_name, ap.base_url, ap.api_key))


@aii_router.post("/remote/provider/check/")
async def check_remote_provider(provider: AiiProviderPublic) -> ReturnDto:
    try:
        count = len(await s_list_remote_provider_models(provider.base_url, provider.api_key))
        return ReturnDto(result=count)
    except TypeError:
        return ReturnDto(success=False)
