import { type ReactNode } from "react";

// 轻量 Markdown 渲染 —— 零依赖、行级解析，覆盖报告正文用到的子集：
// # / ## / ### 标题、**粗** *斜* `码`、[[双链]]、- 与 1. 列表、> 引用、--- 分隔、段落。
// 流式安全：每个 token 重渲染，残缺语法也能容忍。onLink 非空时 [[名称]] 可点（Obsidian 式）。

// 行内：把一段文本切成 [[双链]] / **粗** / *斜* / `码` / 纯文本节点。
function inline(text: string, keyPrefix: string, onLink?: (name: string) => void): ReactNode[] {
  const out: ReactNode[] = [];
  const re = /(\[\[([^\]]+)\]\]|\*\*([^*]+)\*\*|`([^`]+)`|\*([^*]+)\*)/g;
  let last = 0;
  let m: RegExpExecArray | null;
  let i = 0;
  while ((m = re.exec(text)) !== null) {
    if (m.index > last) out.push(text.slice(last, m.index));
    const key = `${keyPrefix}-${i++}`;
    if (m[2] !== undefined) {
      const name = m[2].split("|")[0].trim(); // 支持 [[名称|别名]]
      const label = m[2].includes("|") ? m[2].split("|")[1].trim() : m[2];
      out.push(
        <button key={key} onClick={() => onLink?.(name)} className="rounded bg-brand/10 px-1 text-brand-400 hover:bg-brand/20">
          {label}
        </button>,
      );
    } else if (m[3] !== undefined) out.push(<strong key={key} className="font-semibold text-slate-100">{m[3]}</strong>);
    else if (m[4] !== undefined) out.push(<code key={key} className="rounded bg-ink-800 px-1 py-0.5 font-mono text-[0.85em] text-accent-400">{m[4]}</code>);
    else if (m[5] !== undefined) out.push(<em key={key} className="italic text-slate-300">{m[5]}</em>);
    last = re.lastIndex;
  }
  if (last < text.length) out.push(text.slice(last));
  return out;
}

export function Markdown({ text, className, onLink }: { text: string; className?: string; onLink?: (name: string) => void }) {
  const il = (t: string, k: string) => inline(t, k, onLink);
  const lines = text.replace(/\r\n/g, "\n").split("\n");
  const blocks: ReactNode[] = [];
  let para: string[] = [];
  let list: { ordered: boolean; items: string[] } | null = null;
  let tableBuf: string[] = []; // 连续的 | … | 行，flush 时判定是否真表格
  let code: { lang: string; lines: string[] } | null = null; // ``` 围栏代码块
  let k = 0;

  const cells = (r: string) => r.replace(/^\s*\|/, "").replace(/\|\s*$/, "").split("|").map((c) => c.trim());
  const isSep = (s: string) => s.includes("-") && /^\s*\|?[\s:|-]+\|?\s*$/.test(s);
  const flushTable = () => {
    if (!tableBuf.length) return;
    if (tableBuf.length >= 2 && isSep(tableBuf[1])) {
      const head = cells(tableBuf[0]);
      const rows = tableBuf.slice(2).map(cells);
      blocks.push(
        <div key={`tw${k++}`} className="my-2 overflow-x-auto">
          <table className="w-full border-collapse text-[13px]">
            <thead>
              <tr>{head.map((c, i) => <th key={i} className="border border-line bg-ink-800 px-2 py-1 text-left font-medium text-slate-200">{il(c, `th${k}-${i}`)}</th>)}</tr>
            </thead>
            <tbody>
              {rows.map((r, ri) => (
                <tr key={ri}>{r.map((c, ci) => <td key={ci} className="border border-line px-2 py-1 align-top text-slate-300">{il(c, `td${k}-${ri}-${ci}`)}</td>)}</tr>
              ))}
            </tbody>
          </table>
        </div>,
      );
    } else {
      para.push(...tableBuf); // 不是合法表格 → 当普通段落
    }
    tableBuf = [];
  };

  const flushPara = () => {
    if (para.length) {
      blocks.push(
        <p key={`p${k++}`} className="my-2 leading-relaxed text-slate-300">
          {il(para.join(" "), `p${k}`)}
        </p>,
      );
      para = [];
    }
  };
  const flushList = () => {
    if (list) {
      const items = list.items.map((it, idx) => (
        <li key={idx} className="leading-relaxed text-slate-300">
          {il(it, `li${k}-${idx}`)}
        </li>
      ));
      blocks.push(
        list.ordered ? (
          <ol key={`l${k++}`} className="my-2 ml-5 list-decimal space-y-1 marker:text-slate-500">{items}</ol>
        ) : (
          <ul key={`l${k++}`} className="my-2 ml-5 list-disc space-y-1 marker:text-slate-600">{items}</ul>
        ),
      );
      list = null;
    }
  };

  const flushAll = () => { flushTable(); flushPara(); flushList(); };

  for (const raw of lines) {
    const line = raw.trimEnd();

    // 围栏代码块 ```lang … ```（含未被图表分流的普通代码）。
    if (code) {
      if (line.trim().startsWith("```")) {
        blocks.push(<pre key={`c${k++}`} className="my-2 overflow-x-auto rounded-md border border-line bg-ink-950/60 p-2.5 font-mono text-[12px] leading-relaxed text-slate-300">{code.lines.join("\n")}</pre>);
        code = null;
      } else code.lines.push(raw);
      continue;
    }
    if (line.trim().startsWith("```")) {
      flushAll();
      code = { lang: line.trim().slice(3), lines: [] };
      continue;
    }
    // 表格行：连续的 | … | 缓冲，flush 时判定真伪。
    if (line.trim().startsWith("|")) {
      flushPara();
      flushList();
      tableBuf.push(line);
      continue;
    }

    const h = /^(#{1,3})\s+(.*)$/.exec(line);
    const ol = /^\d+\.\s+(.*)$/.exec(line);
    const ul = /^[-*]\s+(.*)$/.exec(line);

    if (line.trim() === "") {
      flushAll();
    } else if (/^(---|\*\*\*|___)\s*$/.test(line)) {
      flushAll();
      blocks.push(<hr key={`hr${k++}`} className="my-3 border-line" />);
    } else if (h) {
      flushTable();
      flushPara();
      flushList();
      const lvl = h[1].length;
      const cls = lvl === 1 ? "mt-1 mb-3 text-xl font-bold text-slate-100" : lvl === 2 ? "mt-4 mb-2 text-base font-semibold text-slate-100" : "mt-3 mb-1 text-sm font-semibold text-slate-200";
      const content = il(h[2], `h${k}`);
      blocks.push(lvl === 1 ? <h1 key={`h${k++}`} className={cls}>{content}</h1> : lvl === 2 ? <h2 key={`h${k++}`} className={cls}>{content}</h2> : <h3 key={`h${k++}`} className={cls}>{content}</h3>);
    } else if (line.startsWith(">")) {
      flushAll();
      blocks.push(
        <blockquote key={`q${k++}`} className="my-2 border-l-2 border-brand/50 pl-3 text-sm text-slate-400">
          {il(line.replace(/^>\s?/, ""), `q${k}`)}
        </blockquote>,
      );
    } else if (ol) {
      flushTable();
      flushPara();
      if (!list || !list.ordered) {
        flushList();
        list = { ordered: true, items: [] };
      }
      list.items.push(ol[1]);
    } else if (ul) {
      flushTable();
      flushPara();
      if (!list || list.ordered) {
        flushList();
        list = { ordered: false, items: [] };
      }
      list.items.push(ul[1]);
    } else {
      flushTable();
      flushList();
      para.push(line);
    }
  }
  if (code) blocks.push(<pre key={`c${k++}`} className="my-2 overflow-x-auto rounded-md border border-line bg-ink-950/60 p-2.5 font-mono text-[12px] text-slate-300">{code.lines.join("\n")}</pre>);
  flushAll();

  return <div className={className}>{blocks}</div>;
}
