"""
api.v1.assistant — 工作台 AI 助手入口的意图路由（方案 B）。

POST /api/v1/assistant/route  {input}
  → 用一次轻量 LLM 分类把用户的自然语言请求分发给最合适的智能体。
    返回 {matched, agent_id, agent_name, reason}；分类不可用（没配
    云端 key 且本地 ollama 不在）或拿不准时 matched=false，前端回退
    到手动选择器（方案 A 动线）— 路由永远只是加速器，不是单点。

分类模型选择：dashscope qwen-turbo（几乎免费）> 本地 ollama > 不可用。
分类调用走 lambdagent provider（与 pipeline default_judge 同一模式），
usage 随响应返回，成本可审计。
"""
from __future__ import annotations

import json
import os
import re
from typing import Callable, Optional

from fastapi import APIRouter, Depends
from pydantic import BaseModel, Field

from agentpaas.api.deps import get_tenant, get_database
from agentpaas.api.middleware.auth import TenantContext
from agentpaas.db.models import Database

router = APIRouter(prefix="/assistant", tags=["assistant"])

_MAX_INPUT_CHARS = 500
_MAX_CANDIDATES = 12

_CLASSIFY_SYS = (
    "你是智能体调度员。根据用户请求，从候选智能体列表中选出最合适的一个。\n"
    "只输出一个 JSON：{\"choice\": <编号>, \"reason\": \"一句话理由\"}。\n"
    "都不合适或拿不准时输出 {\"choice\": 0}。不要输出其他内容。"
)


def _pick_classifier_model() -> Optional[dict]:
    """选分类模型：dashscope qwen-turbo > 本地 ollama > None（不可用）。"""
    if os.environ.get("DASHSCOPE_API_KEY"):
        return {"provider": "dashscope", "name": "qwen-turbo"}
    try:
        import urllib.request
        with urllib.request.urlopen("http://127.0.0.1:11434/api/tags", timeout=2) as r:
            models = [m["name"] for m in json.loads(r.read()).get("models", [])]
        if models:
            name = next((m for m in models if m.startswith("qwen2.5:")), models[0])
            return {"provider": "ollama", "name": name}
    except Exception:
        pass
    return None


def _llm_classify(user_input: str, candidates: list, model: dict) -> tuple:
    """返回 (choice_index_1based_or_0, reason, usage)。异常向上抛。"""
    from lambdagent.providers import create_provider, ChatMessage

    listing = "\n".join(
        f"{i}. {c['name']} — {c['description'][:80]}"
        for i, c in enumerate(candidates, 1))
    user = (f"用户请求：{user_input[:_MAX_INPUT_CHARS]}\n\n"
            f"候选智能体：\n{listing}")
    kwargs: dict = {"timeout": 30}
    if model.get("name"):
        kwargs["model"] = model["name"]
    p = create_provider(model["provider"], **kwargs)
    resp = p.chat_typed(
        [ChatMessage(role="system", content=_CLASSIFY_SYS),
         ChatMessage(role="user", content=user)],
        temperature=0.0, max_tokens=128)
    usage = {"provider": model["provider"],
             "input_tokens": getattr(resp, "input_tokens", 0),
             "output_tokens": getattr(resp, "output_tokens", 0)}

    text = resp.text.strip()
    m = re.search(r'\{[^{}]*"choice"[^{}]*\}', text)
    if m:
        try:
            d = json.loads(m.group(0))
            return int(d.get("choice", 0)), str(d.get("reason", ""))[:200], usage
        except Exception:
            pass
    m = re.search(r"\d+", text)  # 退化：模型只回了个数字
    return (int(m.group(0)) if m else 0), "", usage


# 可注入的分类函数（测试用）：(input, candidates, model) -> (choice, reason, usage)
_classify_fn: Callable = _llm_classify


class RouteRequest(BaseModel):
    input: str = Field(..., min_length=1, description="用户的自然语言请求")


@router.post("/route")
async def route_request(
    req: RouteRequest,
    tenant: TenantContext = Depends(get_tenant),
    db: Database = Depends(get_database),
):
    """把自然语言请求路由到最合适的智能体（拿不准则 matched=false）。"""
    agents = db.fetchall(
        "SELECT id, name, description FROM agents "
        "WHERE tenant_id = ? AND status = 'active' "
        "ORDER BY updated_at DESC LIMIT ?",
        (tenant.tenant_id, _MAX_CANDIDATES))
    if not agents:
        return {"matched": False, "reason": "no agents"}
    if len(agents) == 1:
        return {"matched": True, "agent_id": agents[0]["id"],
                "agent_name": agents[0]["name"], "reason": "唯一智能体", "usage": None}

    model = _pick_classifier_model()
    if model is None:
        return {"matched": False, "reason": "no classifier model available"}

    candidates = [{"name": a["name"], "description": a.get("description") or ""}
                  for a in agents]
    try:
        choice, reason, usage = _classify_fn(req.input, candidates, model)
    except Exception as e:
        return {"matched": False, "reason": f"classify failed: {e}"}

    if not (1 <= choice <= len(agents)):
        return {"matched": False, "reason": reason or "分类器拿不准", "usage": usage}
    picked = agents[choice - 1]
    return {"matched": True, "agent_id": picked["id"],
            "agent_name": picked["name"], "reason": reason, "usage": usage}
