/**
 * Micron markup → HTML renderer for the editor preview pane.
 * Spec: https://github.com/fr33n0w/micron-composer
 */

function escapeHtml(text: string): string {
  return text
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;");
}

/** Render inline Micron formatting codes within a line of text. */
function renderInline(raw: string): string {
  let out = "";
  let i = 0;

  // Track open/close state for toggle-style tags
  let boldOpen = false;
  let italicOpen = false;
  let underOpen = false;
  let fgOpen = false;
  let bgOpen = false;
  let alignOpen = false;

  while (i < raw.length) {
    // Backtick formatting codes
    if (raw[i] === "`") {
      const code = raw[i + 1];
      if (code === "!") {
        if (boldOpen) { out += "</strong>"; boldOpen = false; }
        else { out += "<strong>"; boldOpen = true; }
        i += 2; continue;
      } else if (code === "*") {
        if (italicOpen) { out += "</em>"; italicOpen = false; }
        else { out += "<em>"; italicOpen = true; }
        i += 2; continue;
      } else if (code === "_") {
        if (underOpen) { out += "</u>"; underOpen = false; }
        else { out += "<u>"; underOpen = true; }
        i += 2; continue;
      } else if (code === "`") {
        // Reset all
        if (boldOpen) { out += "</strong>"; boldOpen = false; }
        if (italicOpen) { out += "</em>"; italicOpen = false; }
        if (underOpen) { out += "</u>"; underOpen = false; }
        if (fgOpen) { out += "</span>"; fgOpen = false; }
        if (bgOpen) { out += "</span>"; bgOpen = false; }
        if (alignOpen) { out += "</span>"; alignOpen = false; }
        i += 2; continue;
      } else if (code === "f") {
        if (fgOpen) { out += "</span>"; fgOpen = false; }
        i += 2; continue;
      } else if (code === "b") {
        if (bgOpen) { out += "</span>"; bgOpen = false; }
        i += 2; continue;
      } else if (code === "a") {
        if (alignOpen) { out += "</span>"; alignOpen = false; }
        i += 2; continue;
      } else if (code === "F") {
        // Foreground color — 3-digit hex only per spec
        const hexMatch = raw.slice(i + 2).match(/^([0-9a-fA-F]{3})/);
        if (hexMatch) {
          if (fgOpen) { out += "</span>"; }
          const [r, g, b] = hexMatch[1].split("");
          const hex = r + r + g + g + b + b;
          out += `<span style="color:#${hex}">`;
          fgOpen = true;
          i += 2 + hexMatch[1].length;
          continue;
        }
      } else if (code === "B") {
        // Background color — 3-digit hex only per spec
        const hexMatch = raw.slice(i + 2).match(/^([0-9a-fA-F]{3})/);
        if (hexMatch) {
          if (bgOpen) { out += "</span>"; }
          const [r, g, b] = hexMatch[1].split("");
          const hex = r + r + g + g + b + b;
          out += `<span style="background:#${hex}">`;
          bgOpen = true;
          i += 2 + hexMatch[1].length;
          continue;
        }
      } else if (code === "c") {
        out += `<span style="display:block;text-align:center">`;
        alignOpen = true; i += 2; continue;
      } else if (code === "r") {
        out += `<span style="display:block;text-align:right">`;
        alignOpen = true; i += 2; continue;
      } else if (code === "l") {
        out += `<span style="display:block;text-align:left">`;
        alignOpen = true; i += 2; continue;
      } else if (code === "<") {
        // Form element: `<...> or `<!...> or `<?...> or `<^...>
        const closeAngle = raw.indexOf(">", i + 2);
        if (closeAngle !== -1) {
          const inner = raw.slice(i + 2, closeAngle);
          out += renderFormTag(inner);
          i = closeAngle + 1;
          continue;
        }
      } else if (code === "[") {
        // Link with inline formatting: `[`!Label`!`:/dest]
        const closeBracket = raw.indexOf("]", i + 2);
        if (closeBracket !== -1) {
          const inner = raw.slice(i + 2, closeBracket);
          const colonIdx = inner.indexOf("`:");
          if (colonIdx !== -1) {
            const labelRaw = inner.slice(0, colonIdx);
            const dest = inner.slice(colonIdx + 2);
            // Strip formatting tags from label for display
            const label = labelRaw.replace(/`[!*_]/g, "");
            out += `<a href="${escapeHtml(dest)}" style="color:#7dc4e4;text-decoration:underline">${escapeHtml(label)}</a>`;
            i = closeBracket + 1;
            continue;
          }
        }
      }
    }

    // Links: [label`slug] or [label`slug.mu]
    if (raw[i] === "[") {
      const close = raw.indexOf("]", i);
      if (close !== -1) {
        const inner = raw.slice(i + 1, close);
        const backtick = inner.indexOf("`");
        if (backtick !== -1) {
          const label = escapeHtml(inner.slice(0, backtick));
          const slug = escapeHtml(inner.slice(backtick + 1).replace(/\.mu$/, ""));
          out += `<a href="/view/${slug}" style="color:#7dc4e4;text-decoration:underline">${label}</a>`;
          i = close + 1;
          continue;
        }
      }
    }

    out += escapeHtml(raw[i]);
    i++;
  }

  // Close any remaining open tags
  if (boldOpen) out += "</strong>";
  if (italicOpen) out += "</em>";
  if (underOpen) out += "</u>";
  if (fgOpen) out += "</span>";
  if (bgOpen) out += "</span>";
  if (alignOpen) out += "</span>";
  return out;
}

/** Render a Micron form tag `<...> as styled HTML. */
function renderFormTag(inner: string): string {
  const esc = escapeHtml;

  // Text field: width|name`placeholder or name`placeholder
  // Password: !width|name`placeholder
  // Checkbox: ?|name|value`label or ?|name|value|*`label
  // Radio: ^|group|value`label or ^|group|value|*`label

  if (inner.startsWith("?")) {
    // Checkbox
    const backtick = inner.indexOf("`");
    const label = backtick !== -1 ? inner.slice(backtick + 1) : "";
    const checked = inner.includes("|*");
    const box = checked ? "☑" : "☐";
    return `<span style="color:#d4a8f8">${box} ${esc(label)}</span>`;
  }

  if (inner.startsWith("^")) {
    // Radio button
    const backtick = inner.indexOf("`");
    const label = backtick !== -1 ? inner.slice(backtick + 1) : "";
    const selected = inner.includes("|*");
    const dot = selected ? "◉" : "○";
    return `<span style="color:#d4a8f8">${dot} ${esc(label)}</span>`;
  }

  if (inner.startsWith("!")) {
    // Password field
    const backtick = inner.indexOf("`");
    const placeholder = backtick !== -1 ? inner.slice(backtick + 1) : "";
    return `<span style="color:#d4a8f8;border:1px solid rgba(212,168,248,0.3);border-radius:3px;padding:0 4px">🔒 ${esc(placeholder || "••••••")}</span>`;
  }

  // Regular text field: width|name`placeholder or name`placeholder
  const backtick = inner.indexOf("`");
  const placeholder = backtick !== -1 ? inner.slice(backtick + 1) : "";
  return `<span style="color:#d4a8f8;border:1px solid rgba(212,168,248,0.3);border-radius:3px;padding:0 4px">${esc(placeholder || "...")}</span>`;
}


export function renderMicron(source: string): string {
  const lines = source.split("\n");
  const htmlLines: string[] = [];
  let literalMode = false;

  for (const line of lines) {
    // Toggle literal mode on standalone `= line
    if (line.trimEnd() === "`=") {
      literalMode = !literalMode;
      continue;
    }

    // In literal mode — render verbatim
    if (literalMode) {
      htmlLines.push(`<div style="font-family:monospace;opacity:0.75;white-space:pre">${escapeHtml(line)}</div>`);
      continue;
    }

    // Comment lines — hidden in output
    if (line.startsWith("#")) continue;

    // All output uses inline spans — the parent container has white-space:pre
    // so newlines come from the \n join at the end.

    // Depth-4+ indent (before >>> check)
    if (line.startsWith(">>>>")) {
      htmlLines.push(`<span style="color:#c9d1d9;font-style:italic">${renderInline(line.slice(4))}</span>`);
    // Headings
    } else if (line.startsWith(">>>")) {
      htmlLines.push(`<span style="color:#a8c4e8;font-weight:bold">${renderInline(line.slice(3))}</span>`);
    } else if (line.startsWith(">>")) {
      htmlLines.push(`<span style="color:#70c4e8;font-weight:bold">${renderInline(line.slice(2))}</span>`);
    } else if (line.startsWith(">")) {
      htmlLines.push(`<span style="color:#7ee8a2;font-weight:bold">${renderInline(line.slice(1))}</span>`);
    // Dividers: - followed by a non-space, non-dash character
    } else if (/^-[^\s-]/.test(line)) {
      const char = line[1];
      htmlLines.push(`<span style="color:#484f58">${char.repeat(40)}</span>`);
    // Standalone depth-reset "<"
    } else if (line.trim() === "<") {
      htmlLines.push(`<span style="color:#d2a8ff;opacity:0.4">↩ depth reset</span>`);
    // Empty line
    } else if (line.trim() === "") {
      htmlLines.push("");
    } else {
      htmlLines.push(renderInline(line));
    }
  }

  return htmlLines.join("\n");
}
