"""本地可视化静态资源（Chart.js / Mermaid / vis-network）与导出 HTML。

项目约定：导出页不引用互联网 URL（无 http(s)/// 外链）；第三方库由
``scripts/download_viz_res.py`` 下载到 ``src/aicd/res/``，运行时 ``viz_export_html``
将 ``res/`` 拷到 HTML 同级目录。
"""

from __future__ import annotations

import shutil
from pathlib import Path
from typing import Any

# 与 src/aicd/res/ 内文件名一致（由 scripts/download_viz_res.py 拉取）
CHART_JS = "chart.umd.min.js"
MERMAID_JS = "mermaid.min.js"
VIS_JS = "vis-network.min.js"
VIS_CSS = "vis-network.min.css"


def bundled_res_dir() -> Path:
    return Path(__file__).resolve().parent.parent / "res"


def list_bundled_viz_files() -> list[str]:
    d = bundled_res_dir()
    if not d.is_dir():
        return []
    return sorted(
        x.name for x in d.iterdir() if x.is_file() and x.suffix in (".js", ".css")
    )


def reorder_body_scripts_before_vis_usage(html: str) -> str:
    """
    修复错误顺序：内联脚本在 ``<body>`` 里先于 ``res/*.js`` 使用了 ``vis`` / ``Chart``。

    将 ``chart`` / ``mermaid`` / ``vis-network`` 三个 ``<script src>`` 以及紧随的
    ``mermaid.initialize`` 块，整体移到第一个内联 ``<script>`` 之前。
    已正确顺序的 HTML 原样返回。
    """
    lib_mark = f'  <script src="res/{CHART_JS}"></script>'
    if lib_mark not in html:
        return html
    body_i = html.find("<body>")
    if body_i < 0:
        return html
    first_inline = html.find("<script>", body_i)
    lib_start = html.find(lib_mark)
    body_end = html.find("</body>")
    if first_inline < 0 or lib_start < 0 or body_end < 0 or lib_start < first_inline:
        return html
    vis_use = html.find("vis.DataSet", first_inline, lib_start)
    chart_use = html.find("new Chart", first_inline, lib_start)
    if vis_use < 0 and chart_use < 0:
        return html
    big = html[first_inline:lib_start]
    libs = html[lib_start:body_end].strip()
    tail = html[body_end:]
    return html[:first_inline] + libs + "\n\n" + big + "\n\n" + tail


def copy_viz_resources(dest_parent: Path) -> dict[str, Any]:
    """将包内 res 中的 .js/.css 复制到 dest_parent/res/（覆盖同名文件）。"""
    src = bundled_res_dir()
    dst = dest_parent / "res"
    if not src.is_dir():
        return {
            "ok": False,
            "error": "bundled res missing",
            "expected": str(src),
        }
    dst.mkdir(parents=True, exist_ok=True)
    copied: list[str] = []
    for f in src.iterdir():
        if f.is_file() and f.suffix in (".js", ".css"):
            shutil.copy2(f, dst / f.name)
            copied.append(f.name)
    return {"ok": True, "res_dir": str(dst), "files": copied}


# 在三大库加载后执行：Chart / vis-network；Mermaid 用 initialize(startOnLoad)
_VIZ_BOOTSTRAP = """
<script>
(function () {
  var el = document.getElementById("aicd-chart-demo");
  if (el && window.Chart) {
    new Chart(el.getContext("2d"), {
      type: "bar",
      data: {
        labels: ["A", "B", "C", "D"],
        datasets: [{
          label: "示例",
          data: [12, 19, 3, 5],
          backgroundColor: ["#4e79a7", "#f28e2b", "#e15759", "#76b7b2"]
        }]
      },
      options: { responsive: true, plugins: { legend: { display: false } } }
    });
  }
})();
(function () {
  if (!window.vis) return;
  var mount = document.getElementById("aicd-vis-network");
  if (!mount) return;
  var nodes = new vis.DataSet([
    { id: 1, label: "节点A" }, { id: 2, label: "节点B" }, { id: 3, label: "节点C" }
  ]);
  var edges = new vis.DataSet([
    { from: 1, to: 2 }, { from: 2, to: 3 }, { from: 3, to: 1 }
  ]);
  new vis.Network(mount, { nodes: nodes, edges: edges }, {
    physics: { stabilization: true },
    interaction: { hover: true }
  });
})();
</script>
"""


def build_viz_html_document(
    title: str,
    body: str,
    *,
    extra_head: str = "",
    extra_scripts: str = "",
    include_default_chart_vis_init: bool = False,
) -> str:
    """生成引用 ./res/*.js 与 vis 样式的完整 HTML（仅相对路径；禁止在 body/extra 中夹带外链）。"""
    tail = _VIZ_BOOTSTRAP if include_default_chart_vis_init else ""
    return f"""<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8"/>
  <meta name="viewport" content="width=device-width,initial-scale=1"/>
  <title>{_esc(title)}</title>
  <link rel="stylesheet" href="res/{VIS_CSS}"/>
  <style>
    body {{ font-family: system-ui, Segoe UI, Roboto, sans-serif; margin: 1rem; line-height: 1.5; }}
    section {{ margin-bottom: 2rem; }}
    .network {{ width: 100%; height: 480px; border: 1px solid #ccc; border-radius: 6px; }}
    pre.mermaid {{ background: #f8f9fa; padding: 1rem; border-radius: 6px; overflow: auto; }}
  </style>
  {extra_head}
</head>
<body>
{body}
  <script src="res/{CHART_JS}"></script>
  <script src="res/{MERMAID_JS}"></script>
  <script src="res/{VIS_JS}"></script>
  <script>
    mermaid.initialize({{ startOnLoad: true, securityLevel: "loose", theme: "neutral" }});
  </script>
  {tail}
  {extra_scripts}
</body>
</html>
"""


def _esc(s: str) -> str:
    return (
        s.replace("&", "&amp;")
        .replace("<", "&lt;")
        .replace(">", "&gt;")
        .replace('"', "&quot;")
    )


def demo_body_snippet() -> str:
    """内置示例 HTML（无内联脚本；与 include_default_chart_vis_init=True 配对）。"""
    return """
<h1>可视化组件示例（离线 res/）</h1>
<section>
  <h2>Mermaid（流程图 / 时序 / mindmap 等）</h2>
  <pre class="mermaid">
flowchart LR
  A[分析] --> B[图表]
  A --> C[关系图]
  </pre>
</section>
<section>
  <h2>Chart.js</h2>
  <canvas id="aicd-chart-demo" width="640" height="280"></canvas>
</section>
<section>
  <h2>vis-network（关系图）</h2>
  <div id="aicd-vis-network" class="network"></div>
</section>
"""
