import { useMemo } from 'react';

interface MarkdownRendererProps {
  content: string;
  className?: string;
}

/**
 * Lightweight, secure Markdown renderer.
 *
 * 1. HTML-escapes all content first (prevents XSS).
 * 2. Converts common Markdown syntax to HTML.
 *
 * Supported syntax:
 *   - Headings (# ## ### … ######)
 *   - Bold (**text**), Italic (*text*)
 *   - Inline code (`code`)
 *   - Fenced code blocks (```lang … ```)
 *   - Links [text](url) → target=_blank rel=noopener
 *   - Unordered lists (- or *)
 *   - Ordered lists (1. 2. …)
 *   - Blockquotes (> text)
 *   - Horizontal rules (--- or ***)
 *   - Tables (| col | col |)
 *   - Line breaks (two trailing spaces or blank line)
 */
export function MarkdownRenderer({ content, className = '' }: MarkdownRendererProps) {
  const html = useMemo(() => renderMarkdown(content), [content]);

  return (
    <div
      className={`markdown-body ${className}`}
      dangerouslySetInnerHTML={{ __html: html }}
    />
  );
}

// ---- converter ----

function renderMarkdown(text: string): string {
  // 1. HTML-escape
  let html = escapeHTML(text);

  // 2. Fenced code blocks (before other transformations — they contain raw markdown chars)
  html = html.replace(
    /```(\w*)\n([\s\S]*?)```/g,
    (_: string, lang: string, code: string) =>
      `<pre><code class="language-${lang || 'text'}">${code.trim()}</code></pre>`
  );

  // 3. Headings (after code blocks to avoid matching # comments in code)
  html = html.replace(/^###### (.+)$/gm, '<h6>$1</h6>');
  html = html.replace(/^##### (.+)$/gm, '<h5>$1</h5>');
  html = html.replace(/^#### (.+)$/gm, '<h4>$1</h4>');
  html = html.replace(/^### (.+)$/gm, '<h3>$1</h3>');
  html = html.replace(/^## (.+)$/gm, '<h2>$1</h2>');
  html = html.replace(/^# (.+)$/gm, '<h1>$1</h1>');

  // 4. Horizontal rules
  html = html.replace(/^(---|\*\*\*)$/gm, '<hr />');

  // 5. Blockquotes
  html = html.replace(/^&gt; (.+)$/gm, '<blockquote>$1</blockquote>');

  // 6. Bold and italic
  html = html.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
  html = html.replace(/(?<!\*)\*(.+?)\*(?!\*)/g, '<em>$1</em>');

  // 7. Inline code (already escaped, just wrap)
  html = html.replace(/`([^`]+)`/g, '<code class="inline-code">$1</code>');

  // 8. Links [text](url) — open in new tab
  html = html.replace(
    /\[([^\]]+)\]\(([^)]+)\)/g,
    '<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>'
  );

  // 9. Images ![alt](url) — after links to avoid false match
  html = html.replace(
    /!\[([^\]]*)\]\(([^)]+)\)/g,
    '<img src="$2" alt="$1" loading="lazy" />'
  );

  // 10. Tables — detect lines with at least two | separators
  const lines = html.split('\n');
  const result: string[] = [];
  let inTable = false;

  for (let i = 0; i < lines.length; i++) {
    const line = lines[i];
    const isTableLine = /^\|.*\|.*\|/.test(line);
    const isSepLine = /^\|[\s\-:|]+\|/.test(line);

    if (isTableLine) {
      if (!inTable) {
        result.push('<table>');
        inTable = true;
      }

      if (isSepLine) {
        // Alignment separator row — skip rendering but use for alignment info
        continue;
      }

      const cells = line
        .replace(/^\|/, '')
        .replace(/\|$/, '')
        .split('|')
        .map((c) => c.trim());

      const isFirstRow = inTable && result[result.length - 1] === '<table>';
      const tag = isFirstRow ? 'th' : 'td';
      result.push(
        '<tr>' + cells.map((c) => `<${tag}>${c}</${tag}>`).join('') + '</tr>'
      );
    } else {
      if (inTable) {
        result.push('</table>');
        inTable = false;
      }
      result.push(line);
    }
  }
  if (inTable) {
    result.push('</table>');
  }
  html = result.join('\n');

  // 11. Unordered lists
  html = html.replace(/^[\-\*] (.+)$/gm, '<li>$1</li>');
  html = html.replace(/((?:<li>.*<\/li>\n?)+)/g, '<ul>$1</ul>');

  // 12. Ordered lists
  html = html.replace(/^\d+\. (.+)$/gm, '<li>$1</li>');
  // Wrap consecutive <li> blocks that aren't already inside a <ul>
  // (This is a simplification — real markdown would need a proper parser)

  // 13. Paragraphs: wrap remaining text lines in <p>, skip already-tagged lines
  const finalLines = html.split('\n');
  const out: string[] = [];
  let para: string[] = [];

  function flushPara() {
    if (para.length > 0) {
      out.push('<p>' + para.join('\n') + '</p>');
      para = [];
    }
  }

  for (const l of finalLines) {
    const isBlock =
      /^<(h[1-6]|ul|ol|li|table|pre|blockquote|hr|div|p|tr|th|td|thead|tbody|img)/.test(l) ||
      /^<\/(ul|ol|table|blockquote|pre|div)>/.test(l) ||
      l === '';

    if (isBlock) {
      flushPara();
      if (l !== '') out.push(l);
    } else {
      para.push(l);
    }
  }
  flushPara();

  return out.join('\n');
}

/** Escape HTML special characters. */
function escapeHTML(s: string): string {
  return s
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#039;');
}
