from __future__ import annotations

import asyncio
from typing import TYPE_CHECKING, Any

from aicd.agent.tool_args_coerce import coerce_tool_json_array
from aicd.kit import drawio_spec
from aicd.tools.drawio_embed_export import export_drawio_file_to_png

if TYPE_CHECKING:
    from aicd.agent.tool_router import ToolRouter


def _diagram_drawio_write(router: ToolRouter, args: dict[str, Any]) -> dict[str, Any]:
    out = router._resolve_path(str(args["path"]))
    if out.suffix.lower() not in (".drawio", ".dio", ".xml"):
        return {
            "ok": False,
            "error": "path should end with .drawio (or .dio / .xml for same format)",
        }
    nodes_co = coerce_tool_json_array(args.get("nodes"), "nodes", allow_empty=True)
    if isinstance(nodes_co, dict):
        return nodes_co
    edges_co = coerce_tool_json_array(args.get("edges"), "edges", allow_empty=True)
    if isinstance(edges_co, dict):
        return edges_co
    nodes = nodes_co
    edges = edges_co
    built = drawio_spec.build_drawio_xml(
        nodes,
        edges,
        page_name=str(args.get("page_name") or "Page-1"),
        diagram_id=args.get("diagram_id"),
        cols=int(args.get("layout_cols", 4)),
    )
    if not built.get("ok"):
        return built
    out.parent.mkdir(parents=True, exist_ok=True)
    xml = str(built["xml"])
    out.write_text(xml, encoding="utf-8")
    return {
        "ok": True,
        "path": str(out),
        "node_count": built["node_count"],
        "edge_count": built["edge_count"],
        "diagram_id": built["diagram_id"],
        "hint": "Open with diagrams.net desktop, VS Code Draw.io extension, or https://app.diagrams.net/",
    }


async def _diagram_drawio_export_png(
    router: ToolRouter, args: dict[str, Any]
) -> dict[str, Any]:
    """Playwright 同步 API 不可在 asyncio 事件循环中直接调用，放到线程里执行。"""
    src = router._resolve_path(str(args["drawio_path"]))
    out = router._resolve_path(str(args["output_png_path"]))
    scale = float(args.get("scale", 3))
    transparent = bool(args.get("transparent", False))
    border = int(args.get("border", 2))
    timeout_ms = int(args.get("timeout_ms", 120_000))
    policy = router._policy.check_allowed

    def _sync() -> dict[str, Any]:
        return export_drawio_file_to_png(
            src,
            out,
            policy_check=policy,
            scale=scale,
            transparent=transparent,
            border=border,
            timeout_ms=timeout_ms,
        )

    return await asyncio.to_thread(_sync)


def _diagram_drawio_summarize(router: ToolRouter, args: dict[str, Any]) -> dict[str, Any]:
    p = router._resolve_path(str(args["path"]))
    if not p.is_file():
        return {"ok": False, "error": "file not found"}
    raw = p.read_text(encoding="utf-8", errors="replace")
    raw = drawio_spec.strip_bom_and_xml_decl(raw)
    summ = drawio_spec.summarize_drawio_xml(raw)
    if not summ.get("ok"):
        return summ
    max_v = int(args.get("max_vertices", 200))
    max_e = int(args.get("max_edges", 400))
    verts = summ["vertices"][:max_v]
    edgs = summ["edges"][:max_e]
    return {
        "ok": True,
        "path": str(p),
        "vertex_count": summ["vertex_count"],
        "edge_count": summ["edge_count"],
        "vertices_preview": verts,
        "edges_preview": edgs,
        "truncated": summ["vertex_count"] > max_v or summ["edge_count"] > max_e,
    }


HANDLERS: dict[str, Any] = {
    "diagram_drawio_write": _diagram_drawio_write,
    "diagram_drawio_export_png": _diagram_drawio_export_png,
    "diagram_drawio_summarize": _diagram_drawio_summarize,
}
