import { marked, type RendererThis, type Tokens } from "marked";
import DOMPurify from "dompurify";
import { linkifyTags, linkifyWikilinks } from "@/utils/tags";

function decodeEntities(text: string): string {
  const textarea = document.createElement("textarea");
  textarea.innerHTML = text;
  return textarea.value;
}

export function slugify(text: string): string {
  return text
    .toLowerCase()
    .replace(/<[^>]+>/g, "")
    .replace(/[^\w\s-]/g, "")
    .trim()
    .replace(/\s+/g, "-");
}

export function stripFirstLineTags(text: string): string {
  const match = text.match(/^[ \t]*((?:(?<!\w)#[\w]+(?:\/[\w]+)*[ \t]*)+)\n?/);
  if (!match) return text;
  // Verify every #-token is a tag, not a heading (headings have "# " with space)
  const tokens = match[1].trim().split(/\s+/);
  const allTags = tokens.every((t) => /^#[\w]+(?:\/[\w]+)*$/.test(t));
  if (!allTags) return text;
  return text.slice(match[0].length);
}

const headingRenderer = {
  heading(this: RendererThis, { tokens, depth }: Tokens.Heading): string {
    const text = this.parser.parseInline(tokens);
    const id = slugify(text);
    return `<h${depth} id="${id}">${text}</h${depth}>`;
  },
};

marked.use({ renderer: headingRenderer });

const PURIFY_OPTS_FULL = {
  ADD_ATTR: ["data-tag", "data-title", "data-task-index"],
  FORCE_BODY: true,
};

const PURIFY_OPTS_PREVIEW = {
  FORBID_TAGS: ["a", "img"],
  FORCE_BODY: true,
};

export function renderMarkdown(text: string, { interactiveCheckboxes = false } = {}): string {
  const stripped = stripFirstLineTags(text);
  const decoded = decodeEntities(stripped);
  let html = marked(decoded) as string;

  if (interactiveCheckboxes) {
    // marked renders task-list checkboxes as <input ... disabled="" ...>.
    // Remove disabled and stamp a sequential data-task-index so the viewer
    // can identify which item was toggled regardless of attribute order.
    html = html.replace(/ disabled=""/g, "");
    let taskIdx = 0;
    html = html.replace(/<input ([^>]*type="checkbox"[^>]*)>/g, (_m, attrs) => {
      return `<input data-task-index="${taskIdx++}" ${attrs}>`;
    });
  }

  const withTags = linkifyTags(html);
  const withLinks = linkifyWikilinks(withTags);
  const sanitized = DOMPurify.sanitize(withLinks, PURIFY_OPTS_FULL);
  // marked escapes ' to &#39; — replace after sanitization to ensure clean rendering
  return sanitized.replace(/&#39;/g, "'");
}

export function renderPreview(text: string): string {
  const stripped = stripFirstLineTags(text);
  const decoded = decodeEntities(stripped);
  const html = marked(decoded) as string;
  const withTags = linkifyTags(html);
  const withLinks = linkifyWikilinks(withTags);
  const sanitized = DOMPurify.sanitize(withLinks, PURIFY_OPTS_PREVIEW);
  return sanitized.replace(/&#39;/g, "'");
}
