import assert from "node:assert/strict";
import { createRequire } from "node:module";
import test from "node:test";

const require = createRequire(import.meta.url);
const marked = require("../web/static/vendor/markdown/marked.umd.js");
globalThis.window = { marked };

const { normalizeMarkdownFences, renderMd, renderMermaidIn } = await import("../web/static/js/markdown.js");

test("repairs equal-length nested markdown fences", () => {
  const broken = [
    "```markdown",
    "```mermaid",
    "flowchart LR",
    "    A --> B",
    "```",
    "```",
    "",
    "正文 **正常**。",
    "",
  ].join("\n");

  const repaired = normalizeMarkdownFences(broken);

  assert.match(repaired, /^````markdown\n```mermaid/);
  assert.match(repaired, /```\n````\n\n正文 \*\*正常\*\*。/);
  const html = renderMd(broken);
  assert.match(html, /<p>正文 <strong>正常<\/strong>。<\/p>/);
});

test("preserves unrelated unclosed fences", () => {
  const broken = "正文\n```python\nprint('x')\n";
  assert.equal(normalizeMarkdownFences(broken), broken);
});

function fakeMermaidBlock(source = "flowchart LR\nA --> B") {
  const created = [];
  const doc = {
    createElement(tag) {
      const el = {
        tag,
        children: [],
        attributes: {},
        appendChild(child) { this.children.push(child); },
        setAttribute(name, value) { this.attributes[name] = value; },
      };
      created.push(el);
      return el;
    },
  };
  const pre = {
    isConnected: true,
    ownerDocument: doc,
    beforeNodes: [],
    before(node) { this.beforeNodes.push(node); },
    replaceWith(node) { this.replacement = node; },
  };
  const code = { dataset: {}, textContent: source, parentElement: pre };
  const container = { querySelectorAll() { return [code]; } };
  return { code, pre, container, created };
}

test("renders completed mermaid blocks with strict local configuration", async () => {
  const calls = { initialize: [], render: [] };
  window.mermaid = {
    initialize(config) { calls.initialize.push(config); },
    async render(id, source) {
      calls.render.push({ id, source });
      return { svg: "<svg viewBox='0 0 10 10'></svg>" };
    },
  };
  const fixture = fakeMermaidBlock();

  const result = await renderMermaidIn(fixture.container);

  assert.deepEqual(result, { rendered: 1, failed: 0, unavailable: 0 });
  assert.equal(calls.initialize.length, 1);
  assert.equal(calls.initialize[0].securityLevel, "strict");
  assert.equal(calls.initialize[0].startOnLoad, false);
  assert.equal(calls.render[0].source, "flowchart LR\nA --> B");
  assert.equal(fixture.pre.replacement.className, "mermaid-diagram");
  assert.equal(fixture.pre.replacement.children[0].innerHTML, "<svg viewBox='0 0 10 10'></svg>");
});

test("keeps mermaid source visible when syntax is invalid", async () => {
  window.mermaid.render = async () => { throw new Error("parse failed"); };
  const fixture = fakeMermaidBlock("not valid");

  const result = await renderMermaidIn(fixture.container);

  assert.deepEqual(result, { rendered: 0, failed: 1, unavailable: 0 });
  assert.equal(fixture.pre.replacement, undefined);
  assert.equal(fixture.pre.beforeNodes[0].textContent, "Mermaid 图表语法有误，已保留源码。");
  assert.equal(fixture.code.dataset.mermaidState, "error");
});
