// Tiny markdown renderer — handles the subset used in softbuild.dev content:
// headings (### / ####), paragraphs, ordered + unordered lists (nested 2-space),
// code blocks (```lang\n...\n```), inline code, bold (**), italic (*),
// links [text](url), images ![alt](url), blockquotes (>).
//
// Returns a React element tree. No external deps.

(function () {
  const { useMemo } = React;

  function renderInline(text) {
    // Escape angle brackets first? Markdown allows raw HTML but we'll keep simple.
    // We'll tokenize against: images, links, inline code, bold, italic.
    const out = [];
    let i = 0;
    let key = 0;
    const push = (node) => out.push(typeof node === "string"
      ? <React.Fragment key={key++}>{node}</React.Fragment>
      : React.cloneElement(node, { key: key++ }));

    while (i < text.length) {
      // Image ![alt](url)
      const img = /^!\[([^\]]*)\]\(([^)]+)\)/.exec(text.slice(i));
      if (img) {
        push(<img src={img[2]} alt={img[1]} className="md-img" />);
        i += img[0].length; continue;
      }
      // Link [text](url)
      const link = /^\[([^\]]+)\]\(([^)]+)\)/.exec(text.slice(i));
      if (link) {
        const isExternal = /^https?:\/\//.test(link[2]);
        push(<a className="link" href={link[2]} target={isExternal ? "_blank" : undefined} rel={isExternal ? "noreferrer" : undefined}>{link[1]}</a>);
        i += link[0].length; continue;
      }
      // Inline code `...`
      const code = /^`([^`]+)`/.exec(text.slice(i));
      if (code) {
        push(<code className="md-code-inline">{code[1]}</code>);
        i += code[0].length; continue;
      }
      // Bold **...**
      const b = /^\*\*([^*]+)\*\*/.exec(text.slice(i));
      if (b) {
        push(<strong>{b[1]}</strong>);
        i += b[0].length; continue;
      }
      // Italic *...*  (avoid being captured by bold above)
      const it = /^\*([^*\n]+)\*/.exec(text.slice(i));
      if (it) {
        push(<em>{it[1]}</em>);
        i += it[0].length; continue;
      }
      // Plain char — consume until next special start
      let j = i + 1;
      while (j < text.length && !"![`*".includes(text[j])) j++;
      push(text.slice(i, j));
      i = j;
    }
    return out;
  }

  function renderMarkdown(md) {
    if (!md) return null;
    const lines = md.replace(/\r\n/g, "\n").split("\n");
    const blocks = [];
    let i = 0;
    let key = 0;
    const k = () => key++;

    while (i < lines.length) {
      const line = lines[i];

      // Blank line
      if (!line.trim()) { i++; continue; }

      // Code block ```
      if (/^```/.test(line)) {
        const lang = line.replace(/^```/, "").trim();
        const buf = [];
        i++;
        while (i < lines.length && !/^```/.test(lines[i])) { buf.push(lines[i]); i++; }
        i++; // skip closing fence
        blocks.push(
          <pre key={k()} className="md-pre">
            {lang && <span className="md-pre-lang">{lang}</span>}
            <code>{buf.join("\n")}</code>
          </pre>
        );
        continue;
      }

      // Heading
      const h = /^(#{1,6})\s+(.*)$/.exec(line);
      if (h) {
        const level = h[1].length;
        const Tag = "h" + Math.min(6, Math.max(2, level));
        blocks.push(React.createElement(Tag, { key: k(), className: "md-h" + level },
          renderInline(h[2].trim())));
        i++;
        continue;
      }

      // Blockquote
      if (/^>\s?/.test(line)) {
        const buf = [];
        while (i < lines.length && /^>\s?/.test(lines[i])) {
          buf.push(lines[i].replace(/^>\s?/, "")); i++;
        }
        blocks.push(<blockquote key={k()}>{renderInline(buf.join(" "))}</blockquote>);
        continue;
      }

      // Table (| col | col |)
      if (/^\|.+\|\s*$/.test(line) && i + 1 < lines.length && /^\|[-:|\s]+\|\s*$/.test(lines[i + 1])) {
        const head = line.split("|").slice(1, -1).map(s => s.trim());
        i += 2;
        const rows = [];
        while (i < lines.length && /^\|.+\|\s*$/.test(lines[i])) {
          rows.push(lines[i].split("|").slice(1, -1).map(s => s.trim()));
          i++;
        }
        blocks.push(
          <div key={k()} className="md-table-wrap">
            <table className="md-table">
              <thead><tr>{head.map((h, j) => <th key={j}>{renderInline(h)}</th>)}</tr></thead>
              <tbody>
                {rows.map((r, ri) => (
                  <tr key={ri}>{r.map((c, ci) => <td key={ci}>{renderInline(c)}</td>)}</tr>
                ))}
              </tbody>
            </table>
          </div>
        );
        continue;
      }

      // List (ordered or unordered, with nested 2-space indent)
      if (/^(\s*)([-*]|\d+\.)\s+/.test(line)) {
        const parsed = parseList(lines, i);
        blocks.push(renderList(parsed.tree, k()));
        i = parsed.next;
        continue;
      }

      // Paragraph — accumulate consecutive non-empty, non-special lines
      const buf = [line];
      i++;
      while (i < lines.length
             && lines[i].trim()
             && !/^#{1,6}\s/.test(lines[i])
             && !/^```/.test(lines[i])
             && !/^>\s?/.test(lines[i])
             && !/^(\s*)([-*]|\d+\.)\s+/.test(lines[i])) {
        buf.push(lines[i]); i++;
      }
      blocks.push(<p key={k()}>{renderInline(buf.join(" "))}</p>);
    }
    return blocks;
  }

  // Parse nested list. Returns { tree: [{ ordered, items: [{ text, children }] }], next }
  function parseList(lines, start) {
    function parseAt(idx, indent) {
      const items = [];
      let ordered = null;
      while (idx < lines.length) {
        const m = /^(\s*)([-*]|\d+\.)\s+(.*)$/.exec(lines[idx]);
        if (!m) {
          if (!lines[idx].trim()) { idx++; continue; }
          break;
        }
        const lineIndent = m[1].length;
        if (lineIndent < indent) break;
        if (lineIndent > indent) {
          // sub-list belongs to last item
          const sub = parseAt(idx, lineIndent);
          if (items.length) items[items.length - 1].children = sub.list;
          idx = sub.next;
          continue;
        }
        const isOrdered = /\d+\./.test(m[2]);
        if (ordered === null) ordered = isOrdered;
        items.push({ text: m[3], children: null });
        idx++;
      }
      return { list: { ordered: !!ordered, items }, next: idx };
    }
    const r = parseAt(start, /^(\s*)/.exec(lines[start])[1].length);
    return { tree: [r.list], next: r.next };
  }

  function renderList(tree, baseKey) {
    let key = 0;
    const k = () => `${baseKey}-${key++}`;
    function render(list) {
      const Tag = list.ordered ? "ol" : "ul";
      return (
        <Tag key={k()} className="md-list">
          {list.items.map((it, i) => (
            <li key={i}>
              {renderInline(it.text)}
              {it.children && render(it.children)}
            </li>
          ))}
        </Tag>
      );
    }
    return render(tree[0]);
  }

  function Markdown({ source }) {
    const tree = useMemo(() => renderMarkdown(source), [source]);
    return <div className="md">{tree}</div>;
  }

  window.Markdown = Markdown;
})();
