"""FastAPI 应用定义 — 对外接口

对外仅暴露 4 个接口：
1. GET  /health     — 健康检查
2. GET  /tools      — 查看完整工具表（含分类、工具组、状态）
3. POST /run_tool   — 调用工具
4. POST /chat       — 与 ServiceAgent 对话（客服入口）
"""

from __future__ import annotations

import logging
from typing import Any, TYPE_CHECKING

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field

if TYPE_CHECKING:
    from tool_agent.router.agent import Router
    from tool_agent.service.session import SessionManager

logger = logging.getLogger(__name__)


# ---- 请求/响应模型 ----

class SearchToolsRequest(BaseModel):
    keyword: str | None = None


class RunToolRequest(BaseModel):
    tool_id: str
    params: dict[str, Any] = Field(default_factory=dict)

class RunToolResponse(BaseModel):
    status: str
    result: Any = None
    error: str | None = None

class ChatRequest(BaseModel):
    message: str
    chat_id: str  # 必填，每个对话窗口一个

class ChatResponse(BaseModel):
    response: str
    chat_id: str


def create_app(router: Router, session_manager: SessionManager = None) -> FastAPI:
    app = FastAPI(title="Tool Agent", version="2.0")

    # ---- 1. 健康检查 ----

    @app.get("/health")
    async def health():
        return {"status": "ok"}

    # ---- 2. 查看完整工具表 ----

    @app.get("/tools")
    async def list_tools():
        """返回完整工具表：按后端执行环境分类，包含工具组和运行状态"""

        backend_runtimes = [
            {
                "backend_runtime": "local",
                "name": "本地 Python 运行时",
                "description": "使用 uv 管理的本地 Python 进程，启动快、资源占用少",
            },
            {
                "backend_runtime": "docker",
                "name": "Docker 容器运行时",
                "description": "运行在 Docker 容器中，适合需要系统库、GPU 或隔离环境的场景",
            },
            {
                "backend_runtime": "remote",
                "name": "远程 API / 云端服务",
                "description": "调用外部 API 或云端服务，如 RunComfy、LiblibAI 等",
            },
        ]

        groups = []
        for g in router.registry.group_manager.list_all():
            groups.append({
                "group_id": g.group_id,
                "name": g.name,
                "description": g.description,
                "backend_runtime": g.category.value,
                "tool_ids": g.tool_ids,
                "usage_order": g.usage_order,
                "usage_example": g.usage_example,
            })

        tools = []
        for tool in router.registry.list_all():
            source = router.status_manager.get_primary_source(tool.tool_id)
            route = router.status_manager.get_status(tool.tool_id)
            tools.append({
                "tool_id": tool.tool_id,
                "name": tool.name,
                "description": tool.description,
                "category": tool.category,
                "backend_runtime": tool.backend_runtime.value if tool.backend_runtime else "unknown",
                "group_ids": tool.group_ids,
                "input_schema": tool.input_schema,
                "output_schema": tool.output_schema,
                "state": route.state.value if route else "stopped",
                "port": route.port if route else None,
                "host_dir": source.host_dir if source else None,
                "endpoint_path": source.endpoint_path if source else None,
                "http_method": source.http_method if source else None,
            })

        return {
            "backend_runtimes": backend_runtimes,
            "groups": groups,
            "tools": tools,
            "total": len(tools),
        }

    # ---- 2.5. 检索工具表 ----

    @app.post("/search_tools")
    async def search_tools(request: SearchToolsRequest):
        kw = (request.keyword or "").lower()
        tools = []
        for tool in router.registry.list_all():
            if kw:
                name_str = (tool.name or "").lower()
                desc_str = (tool.description or "").lower()
                id_str = (tool.tool_id or "").lower()
                if kw not in name_str and kw not in desc_str and kw not in id_str:
                    continue

            source = router.status_manager.get_primary_source(tool.tool_id)
            route = router.status_manager.get_status(tool.tool_id)
            
            # 解析 params 兼容老的 CLI 工具
            params = []
            if tool.input_schema and "properties" in tool.input_schema:
                required_fields = tool.input_schema.get("required", [])
                for param_name, param_def in tool.input_schema["properties"].items():
                    params.append({
                        "name": param_name,
                        "type": param_def.get("type", "string"),
                        "required": param_name in required_fields,
                        "description": param_def.get("description", ""),
                        "default": param_def.get("default"),
                        "enum": param_def.get("enum")
                    })

            tools.append({
                "tool_id": tool.tool_id,
                "name": tool.name,
                "description": tool.description,
                "category": tool.category,
                "backend_runtime": tool.backend_runtime.value if tool.backend_runtime else "unknown",
                "group_ids": tool.group_ids,
                "input_schema": tool.input_schema,
                "output_schema": tool.output_schema,
                "params": params,
                "state": route.state.value if route else "stopped",
                "port": route.port if route else None,
                "host_dir": source.host_dir if source else None,
                "endpoint_path": source.endpoint_path if source else None,
                "http_method": source.http_method if source else None,
            })

        return {
            "total": len(tools),
            "tools": tools
        }

    # ---- 3. 调用工具 ----

    @app.post("/run_tool")
    async def run_tool(request: RunToolRequest):
        """调用已注册的工具（Dispatcher 会在需要时自动 start_tool）。"""
        try:
            result = await router.dispatcher.dispatch(request.tool_id, request.params)
            return RunToolResponse(status="success", result=result)
        except Exception as e:
            logger.error(f"run_tool failed: {e}")
            return RunToolResponse(status="error", error=str(e))

    # ---- 4. ServiceAgent 对话 ----

    @app.post("/chat", response_model=ChatResponse)
    async def chat(request: ChatRequest):
        """与 ServiceAgent 对话。每个 chat_id 对应一个独立的客服实例。"""
        if session_manager is None:
            raise HTTPException(status_code=503, detail="SessionManager not initialized")

        try:
            response, chat_id = await session_manager.chat(
                request.message, chat_id=request.chat_id)
            return ChatResponse(response=response, chat_id=chat_id)
        except Exception as e:
            logger.error(f"Chat error: {e}")
            raise HTTPException(status_code=500, detail=str(e))

    return app
