function escapeHtml(value) {
  const map = {
    "&": "&amp;",
    "<": "&lt;",
    ">": "&gt;",
    '"': "&quot;",
    "'": "&#39;"
  };
  return String(value || "").replace(/[&<>"']/g, (char) => map[char]);
}

function safeUrl(value) {
  const raw = String(value || "").trim();
  if (!raw) return "";
  if (/^(https?:\/\/|\/(?!\/)|#)/i.test(raw)) return escapeHtml(raw);
  return "";
}

function renderMarkdownInline(value) {
  let output = escapeHtml(value);
  output = output.replace(/`([^`]+)`/g, "<code>$1</code>");
  output = output.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_match, text, url) => {
    const href = safeUrl(url);
    return href ? `<a href="${href}" target="_blank" rel="noopener noreferrer">${escapeHtml(text)}</a>` : escapeHtml(text);
  });
  output = output.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>");
  output = output.replace(/\*([^*]+)\*/g, "<em>$1</em>");
  return output;
}

function renderMarkdown(value) {
  const lines = String(value || "").replace(/\r\n?/g, "\n").split("\n");
  let html = "";
  let paragraph = [];
  let listType = null;
  let inCode = false;
  let codeLang = "";
  let codeLines = [];

  const flushParagraph = () => {
    if (!paragraph.length) return;
    html += `<p>${renderMarkdownInline(paragraph.join(" "))}</p>`;
    paragraph = [];
  };
  const closeList = () => {
    if (!listType) return;
    html += `</${listType}>`;
    listType = null;
  };

  for (const line of lines) {
    const trimmed = line.trim();
    if (inCode) {
      if (trimmed.startsWith("```")) {
        const langClass = codeLang ? ` class="language-${escapeHtml(codeLang)}"` : "";
        html += `<pre><code${langClass}>${escapeHtml(codeLines.join("\n"))}</code></pre>`;
        inCode = false;
        codeLang = "";
        codeLines = [];
        continue;
      }
      codeLines.push(line);
      continue;
    }
    if (trimmed.startsWith("```")) {
      flushParagraph();
      closeList();
      inCode = true;
      codeLang = trimmed.slice(3).trim().replace(/[^a-z0-9_-]/gi, "").slice(0, 32);
      continue;
    }
    if (!trimmed) {
      flushParagraph();
      closeList();
      continue;
    }
    const heading = trimmed.match(/^(#{1,6})\s+(.*)$/);
    if (heading) {
      flushParagraph();
      closeList();
      const level = heading[1].length;
      html += `<h${level}>${renderMarkdownInline(heading[2])}</h${level}>`;
      continue;
    }
    const list = trimmed.match(/^([*-]|\d+\.)\s+(.*)$/);
    if (list) {
      flushParagraph();
      const nextType = list[1].endsWith(".") ? "ol" : "ul";
      if (listType && listType !== nextType) closeList();
      if (!listType) {
        listType = nextType;
        html += `<${listType}>`;
      }
      html += `<li>${renderMarkdownInline(list[2])}</li>`;
      continue;
    }
    paragraph.push(trimmed);
  }

  if (inCode) {
    const langClass = codeLang ? ` class="language-${escapeHtml(codeLang)}"` : "";
    html += `<pre><code${langClass}>${escapeHtml(codeLines.join("\n"))}</code></pre>`;
  }
  flushParagraph();
  closeList();
  return html || "<p></p>";
}

module.exports = {
  escapeHtml,
  renderMarkdown,
  renderMarkdownInline,
  safeUrl
};
