function escapeHtml(value: string): string {
  return value
    .replaceAll("&", "&amp;")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;")
    .replaceAll('"', "&quot;")
    .replaceAll("'", "&#39;");
}

function escapeAttribute(value: string): string {
  return value.replaceAll("&", "&amp;").replaceAll('"', "&quot;");
}

function normalizeHttpUrl(rawUrl: string): string | null {
  try {
    const parsed = new URL(rawUrl);
    if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return null;
    return parsed.toString();
  } catch {
    return null;
  }
}

function renderInline(markdown: string): string {
  let rendered = escapeHtml(markdown);

  rendered = rendered.replace(/`([^`]+)`/g, (_match, value: string) => `<code>${value}</code>`);
  rendered = rendered.replace(/\*\*([^*]+)\*\*/g, (_match, value: string) => `<strong>${value}</strong>`);
  rendered = rendered.replace(/\*([^*]+)\*/g, (_match, value: string) => `<em>${value}</em>`);
  rendered = rendered.replace(/\[([^\]]+)\]\(([^)\s]+)\)/g, (_match, label: string, url: string) => {
    const safeUrl = normalizeHttpUrl(url);
    if (!safeUrl) return label;
    return `<a href="${escapeAttribute(safeUrl)}" target="_blank" rel="noopener noreferrer">${label}</a>`;
  });

  return rendered;
}

export function markdownToSafeHtml(markdown: string): string {
  const source = markdown.replace(/\r\n/g, "\n").trim();
  if (!source) return "<p>Sin contenido.</p>";

  const lines = source.split("\n");
  const output: string[] = [];
  let listMode: "ol" | "ul" | null = null;

  const closeList = () => {
    if (!listMode) return;
    output.push(listMode === "ol" ? "</ol>" : "</ul>");
    listMode = null;
  };

  for (const rawLine of lines) {
    const line = rawLine.trim();

    if (!line) {
      closeList();
      continue;
    }

    const h3 = line.match(/^###\s+(.+)$/);
    if (h3) {
      closeList();
      output.push(`<h3>${renderInline(h3[1])}</h3>`);
      continue;
    }

    const h2 = line.match(/^##\s+(.+)$/);
    if (h2) {
      closeList();
      output.push(`<h2>${renderInline(h2[1])}</h2>`);
      continue;
    }

    const h1 = line.match(/^#\s+(.+)$/);
    if (h1) {
      closeList();
      output.push(`<h1>${renderInline(h1[1])}</h1>`);
      continue;
    }

    const ordered = line.match(/^\d+\.\s+(.+)$/);
    if (ordered) {
      if (listMode !== "ol") {
        closeList();
        output.push("<ol>");
        listMode = "ol";
      }
      output.push(`<li>${renderInline(ordered[1])}</li>`);
      continue;
    }

    const unordered = line.match(/^[-*]\s+(.+)$/);
    if (unordered) {
      if (listMode !== "ul") {
        closeList();
        output.push("<ul>");
        listMode = "ul";
      }
      output.push(`<li>${renderInline(unordered[1])}</li>`);
      continue;
    }

    const quote = line.match(/^>\s+(.+)$/);
    if (quote) {
      closeList();
      output.push(`<blockquote>${renderInline(quote[1])}</blockquote>`);
      continue;
    }

    closeList();
    output.push(`<p>${renderInline(line)}</p>`);
  }

  closeList();
  return output.join("\n");
}

export function markdownToPlainText(markdown: string): string {
  return markdown
    .replace(/\r\n/g, "\n")
    .replace(/\[([^\]]+)\]\(([^)]+)\)/g, "$1")
    .replace(/[`*_>#-]/g, "")
    .replace(/\n{2,}/g, "\n")
    .trim();
}
