"""Router — 路由层入口

管理工具注册表、状态表、请求分发。
对外通过 FastAPI 暴露 /health, /tools, /run_tool, /chat 接口。
"""

from __future__ import annotations

import asyncio
import logging
from typing import Any

from tool_agent.registry.registry import ToolRegistry
from tool_agent.router.dispatcher import Dispatcher
from tool_agent.router.status import ToolStatusManager

logger = logging.getLogger(__name__)


class Router:
    """路由层：工具状态管理 + 对外 API"""

    def __init__(self) -> None:
        self.registry = ToolRegistry()
        self.status_manager = ToolStatusManager(self.registry)
        self.dispatcher = Dispatcher(self.status_manager)
        self._tasks: dict[str, dict[str, Any]] = {}
        self._coding_agent_tasks: dict[str, asyncio.Task] = {}
        self._session_manager = None  # 由 __main__ 注入

    def set_session_manager(self, sm) -> None:
        self._session_manager = sm

    def create_app(self, session_manager=None):
        from tool_agent.router.server import create_app
        self.app = create_app(self, session_manager=session_manager)
        return self.app

    async def start(self, port: int = 8001) -> None:
        import uvicorn
        config = uvicorn.Config(self.app, host="0.0.0.0", port=port, log_level="info")
        server = uvicorn.Server(config)
        logger.info(f"Router starting on port {port}")
        await server.serve()

    def submit_create_task(self, task_id: str, task_spec: str, reference_files: list[str] = None) -> None:
        self._tasks[task_id] = {"status": "pending", "task_spec": task_spec, "reference_files": reference_files or []}
        task = asyncio.get_event_loop().create_task(self._run_create_task(task_id, task_spec, reference_files or []))
        self._coding_agent_tasks[task_id] = task

    async def _run_create_task(self, task_id: str, task_spec: str, reference_files: list[str]) -> None:
        self._tasks[task_id]["status"] = "running"
        try:
            from pathlib import Path
            from tool_agent.tool.agent import CodingAgent

            # 读取 reference_files 内容
            ref_files_dict = {}
            for file_path in reference_files:
                try:
                    p = Path(file_path)
                    if p.exists():
                        ref_files_dict[file_path] = p.read_text(encoding="utf-8", errors="replace")
                except Exception as e:
                    logger.warning(f"Failed to read reference file {file_path}: {e}")

            agent = CodingAgent()
            result = await agent.execute(task_spec, reference_files=ref_files_dict if ref_files_dict else None)
            self._tasks[task_id].update({"status": "completed", "result": result})
            self.registry._load()
            self.status_manager._sync_from_registry()

            # CodingAgent 完成后，同步点亮 KnowHub 工具表
            await self._sync_knowhub_after_register()
        except Exception as e:
            logger.error(f"Create task {task_id} failed: {e}")
            self._tasks[task_id].update({"status": "failed", "error": str(e)})
        finally:
            self._coding_agent_tasks.pop(task_id, None)

    def get_task_status(self, task_id: str) -> dict[str, Any] | None:
        return self._tasks.get(task_id)

    def get_coding_agent_status(self) -> dict[str, Any]:
        running = [tid for tid, task in self._coding_agent_tasks.items() if not task.done()]
        tasks_summary = []
        for tid, data in list(self._tasks.items())[-10:]:
            tasks_summary.append({
                "task_id": tid,
                "status": data.get("status"),
                "task_spec": data.get("task_spec", "")[:120],
                "error": data.get("error"),
            })
        return {
            "running_count": len(running),
            "running_task_ids": running,
            "queued_count": len([t for t in self._tasks.values() if t.get("status") == "pending"]),
            "recent_tasks": tasks_summary,
        }

    def get_system_status(self) -> dict[str, Any]:
        """全局状态：工具、CodingAgent、ServiceAgent 窗口"""
        status = {
            "tools": {
                "total": len(self.registry.list_all()),
                "active": len([t for t in self.registry.list_all() if t.status.value == "active"]),
            },
            "coding_agent": self.get_coding_agent_status(),
            "service_agent": (
                self._session_manager.get_status()
                if self._session_manager else {"total_windows": 0, "im_connected": False}
            ),
        }
        return status

    def stop_all(self) -> int:
        return self.status_manager.stop_all()

    async def _sync_knowhub_after_register(self) -> None:
        """CodingAgent 注册完工具后，智能匹配 KnowHub 工具表并点亮

        1. 获取所有 registry 工具和 KnowHub 工具
        2. 根据名称、描述、分类等信息智能匹配
        3. 更新双向索引：registry.tool_slug_ids 和 KnowHub.toolhub_items
        4. 点亮已接入的 KnowHub 工具
        """
        try:
            from tool_agent.tool_table import get_client
            from tool_agent.registry.groups import ToolGroupManager

            client = get_client()
            group_manager = ToolGroupManager()
            all_knowhub_tools = client.list_all_tools()

            if not all_knowhub_tools:
                logger.info("KnowHub tool table is empty or unreachable, skipping sync")
                return

            # 构建 KnowHub 工具索引
            knowhub_index = {}  # tool_slug -> knowhub_tool
            for kt in all_knowhub_tools:
                slug = kt.get("metadata", {}).get("tool_slug", "")
                if slug:
                    knowhub_index[slug] = kt

            # 遍历 registry 工具，智能匹配 KnowHub 工具
            matched_map: dict[str, dict] = {}  # slug -> {"tools": [...], "groups": set()}

            for tool in self.registry.list_all():
                matched_slugs = self._match_knowhub_tools(tool, knowhub_index)

                if matched_slugs:
                    # 更新 registry 中的 tool_slug_ids
                    if set(matched_slugs) != set(tool.tool_slug_ids):
                        tool.tool_slug_ids = matched_slugs
                        self.registry.update(tool)
                        logger.info(f"Updated {tool.tool_id} -> {matched_slugs}")

                    # 收集到 matched_map
                    for slug in matched_slugs:
                        if slug not in matched_map:
                            matched_map[slug] = {"tools": [], "groups": set()}
                        matched_map[slug]["tools"].append({tool.tool_id: tool.description})
                        matched_map[slug]["groups"].update(tool.group_ids)

            # 更新 KnowHub 工具表
            for slug, data in matched_map.items():
                kt = knowhub_index.get(slug)
                if not kt:
                    continue

                # 合并工具和组
                items = data["tools"].copy()
                for group_id in data["groups"]:
                    group = group_manager.get_group(group_id)
                    if group:
                        items.append({group_id: group.description})

                try:
                    client.update_toolhub_items(kt["id"], items)
                    client.update_tool_status(kt["id"], "已接入")
                    logger.info(f"Synced {slug}: {len(data['tools'])} tools, {len(data['groups'])} groups")
                except Exception as e:
                    logger.warning(f"Failed to sync {slug}: {e}")

        except Exception as e:
            logger.warning(f"KnowHub sync failed (non-fatal): {e}")

    def _match_knowhub_tools(self, tool, knowhub_index: dict) -> list[str]:
        """智能匹配工具能解决哪些 KnowHub 工具问题

        匹配规则：
        1. 工具名称包含 KnowHub 工具的 slug 或 title
        2. 工具描述包含 KnowHub 工具的关键词
        3. 分类匹配
        """
        matched = []
        tool_name_lower = tool.name.lower()
        tool_id_lower = tool.tool_id.lower()
        tool_desc_lower = tool.description.lower()

        for slug, kt in knowhub_index.items():
            kt_slug = slug.lower()
            kt_title = kt.get("title", "").lower()
            kt_desc = kt.get("metadata", {}).get("description", "").lower()

            # 规则1: 名称匹配
            if kt_slug in tool_name_lower or kt_slug in tool_id_lower:
                matched.append(slug)
                continue
            if kt_title and kt_title in tool_name_lower:
                matched.append(slug)
                continue

            # 规则2: 描述关键词匹配（提取 KnowHub 工具的核心词）
            if kt_desc:
                keywords = [w for w in kt_desc.split() if len(w) > 3][:5]
                if any(kw in tool_desc_lower for kw in keywords):
                    matched.append(slug)
                    continue

        return matched
