import { expect, test } from "vitest";

import { normalizeMermaidMarkdown } from "@/core/streamdown/mermaid";
import { preprocessStreamdownMarkdown } from "@/core/streamdown/preprocess";

test("normalizes labelled dotted arrows inside mermaid fences", () => {
  const markdown = [
    "```mermaid",
    "flowchart TD",
    '    A -- "sealed memory" -.-> F',
    '    B -- "resonance" -.-> A',
    "```",
  ].join("\n");

  expect(normalizeMermaidMarkdown(markdown)).toBe(
    [
      "```mermaid",
      "flowchart TD",
      '    A -. "sealed memory" .-> F',
      '    B -. "resonance" .-> A',
      "```",
    ].join("\n"),
  );
});

test("does not rewrite non-mermaid code fences", () => {
  const markdown = ["```text", 'A -- "sealed memory" -.-> F', "```"].join("\n");

  expect(normalizeMermaidMarkdown(markdown)).toBe(markdown);
});

test("preserves mermaid fence metadata", () => {
  const markdown = [
    '```mermaid title="relationships"',
    'A -- "sealed memory" -.-> F',
    "```",
  ].join("\n");

  expect(normalizeMermaidMarkdown(markdown)).toBe(
    [
      '```mermaid title="relationships"',
      'A -. "sealed memory" .-> F',
      "```",
    ].join("\n"),
  );
});

test("normalizes labelled dotted arrows with inconsistent spacing", () => {
  const markdown = [
    "```mermaid",
    'A--"sealed memory"-.->F',
    'B --"resonance"-.-> A',
    'C-- "handoff" -.->D',
    "```",
  ].join("\n");

  expect(normalizeMermaidMarkdown(markdown)).toBe(
    [
      "```mermaid",
      'A -. "sealed memory" .-> F',
      'B -. "resonance" .-> A',
      'C -. "handoff" .-> D',
      "```",
    ].join("\n"),
  );
});

test("normalizes mermaid fences with CRLF line endings", () => {
  const markdown = ["```mermaid", 'A--"sealed memory"-.->F', "```"].join(
    "\r\n",
  );

  expect(normalizeMermaidMarkdown(markdown)).toBe(
    ["```mermaid", 'A -. "sealed memory" .-> F', "```"].join("\n"),
  );
});

test("preserves empty mermaid fences", () => {
  const markdown = ["```mermaid", "```"].join("\n");

  expect(normalizeMermaidMarkdown(markdown)).toBe(markdown);
});

test("normalizes labelled dotted arrows inside tilde mermaid fences", () => {
  const markdown = ["~~~mermaid", 'A -- "sealed memory" -.-> F', "~~~"].join(
    "\n",
  );

  expect(normalizeMermaidMarkdown(markdown)).toBe(
    ["~~~mermaid", 'A -. "sealed memory" .-> F', "~~~"].join("\n"),
  );
});

test("normalizes mermaid fences with longer backtick closing fences", () => {
  const markdown = ["```mermaid", 'A -- "sealed memory" -.-> F', "````"].join(
    "\n",
  );

  expect(normalizeMermaidMarkdown(markdown)).toBe(
    ["```mermaid", 'A -. "sealed memory" .-> F', "````"].join("\n"),
  );
});

test("normalizes mermaid fences with longer tilde closing fences", () => {
  const markdown = ["~~~mermaid", 'A -- "sealed memory" -.-> F', "~~~~"].join(
    "\n",
  );

  expect(normalizeMermaidMarkdown(markdown)).toBe(
    ["~~~mermaid", 'A -. "sealed memory" .-> F', "~~~~"].join("\n"),
  );
});

test("preprocesses markdown only when mermaid normalization can apply", () => {
  const textOnlyMarkdown = 'A -- "sealed memory" -.-> F';
  const plainMermaidMarkdown = ["```mermaid", "A --> F", "```"].join("\n");
  const labelledMermaidMarkdown = [
    "```mermaid",
    'A -- "sealed memory" -.-> F',
    "```",
  ].join("\n");

  expect(preprocessStreamdownMarkdown(textOnlyMarkdown)).toBe(textOnlyMarkdown);
  expect(preprocessStreamdownMarkdown(plainMermaidMarkdown)).toBe(
    plainMermaidMarkdown,
  );
  expect(preprocessStreamdownMarkdown(labelledMermaidMarkdown)).toBe(
    ["```mermaid", 'A -. "sealed memory" .-> F', "```"].join("\n"),
  );
});
