"use client";

import { useEffect, useState, useCallback, useRef } from "react";
import { marked } from "marked";
import styles from "./lesson-markdown.module.css";

type TocItem = { level: number; text: string; id: string };

function slugify(text: string): string {
  return text
    .replace(/[^\p{L}\p{N}\s-]/gu, "")
    .replace(/\s+/g, "-")
    .toLowerCase();
}

function extractToc(content: string): TocItem[] {
  const items: TocItem[] = [];
  const lines = content.split("\n");
  let idCounter = 0;
  for (const line of lines) {
    const h1 = line.match(/^# (.+)$/);
    const h2 = line.match(/^## (.+)$/);
    if (h1) {
      items.push({ level: 1, text: h1[1].replace(/#{1,6}\s/g, "").trim(), id: `h-${idCounter++}` });
    } else if (h2) {
      items.push({ level: 2, text: h2[1].replace(/#{1,6}\s/g, "").trim(), id: `h-${idCounter++}` });
    }
  }
  return items;
}

function markdownToHtml(content: string): string {
  const raw = marked.parse(content, { breaks: true, gfm: true }) as string;
  let html = raw
    .replace(/<img /g, '<img loading="lazy" decoding="async" ')
    .replace(/<a href=/g, '<a href=');
  // 给 h1/h2 添加 id
  html = html.replace(/<h1>([^<]*)<\/h1>/gi, (_, text) => {
    const t = text.replace(/<[^>]+>/g, "").trim();
    return `<h1 id="${slugify(t)}" class="scroll-mt-24">${text}</h1>`;
  });
  html = html.replace(/<h2>([^<]*)<\/h2>/gi, (_, text) => {
    const t = text.replace(/<[^>]+>/g, "").trim();
    return `<h2 id="${slugify(t)}" class="scroll-mt-24">${text}</h2>`;
  });
  html = html.replace(/<a href="([^"]+)"([^>]*)>/g, '<a href="$1" target="_blank" rel="noopener noreferrer"$2>');
  html = html.replace(/<pre>\s*<code([^>]*)>/g, `<pre class="${styles.codeBlock}"><code$1>`);
  return html;
}

export function LessonMarkdown({ content }: { content: string }) {
  const [readProgress, setReadProgress] = useState(0);
  const [showBackTop, setShowBackTop] = useState(false);
  const [showToc, setShowToc] = useState(false);
  const contentRef = useRef<HTMLDivElement>(null);
  const toc = extractToc(content);
  const html = markdownToHtml(content);

  useEffect(() => {
    let ticking = false;
    const onScroll = () => {
      if (ticking) return;
      ticking = true;
      requestAnimationFrame(() => {
        const scrollTop = window.scrollY || document.documentElement.scrollTop;
        const docHeight = document.documentElement.scrollHeight - window.innerHeight;
        setReadProgress(docHeight > 0 ? Math.min(100, (scrollTop / docHeight) * 100) : 0);
        setShowBackTop(scrollTop > 400);
        ticking = false;
      });
    };
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  const handleTocJump = useCallback((index: number) => {
    setShowToc(false);
    const root = contentRef.current;
    if (!root) return;
    const headings = root.querySelectorAll("h1, h2");
    const el = headings[index] as HTMLElement;
    if (el) {
      el.scrollIntoView({ behavior: "smooth", block: "start" });
    }
  }, []);

  return (
    <>
      <div className={styles.readingProgress} style={{ width: `${readProgress}%` }} />

      <div
        ref={contentRef}
        className={`${styles.markdownBody} markdown-body`}
        dangerouslySetInnerHTML={{ __html: html }}
      />

      <div
        className={`${styles.drawerMask} ${showToc ? styles.drawerMaskOpen : ""}`}
        onClick={() => setShowToc(false)}
        aria-hidden="true"
      />
      <aside className={`${styles.drawer} ${showToc ? styles.drawerOpen : ""}`}>
        <div className={styles.drawerTitle}>目录</div>
        {toc.map((item, i) => (
          <div
            key={item.id}
            role="button"
            tabIndex={0}
            className={item.level === 2 ? `${styles.drawerItem} ${styles.drawerItemH2}` : styles.drawerItem}
            onClick={() => handleTocJump(i)}
            onKeyDown={(e) => {
              if (e.key === "Enter" || e.key === " ") handleTocJump(i);
            }}
          >
            {item.text}
          </div>
        ))}
      </aside>

      {showBackTop && (
        <>
          {toc.length > 0 && (
            <button
              type="button"
              className={styles.tocButton}
              onClick={() => setShowToc(true)}
              aria-label="打开目录"
            >
              <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                <line x1="3" y1="6" x2="21" y2="6" />
                <line x1="3" y1="12" x2="21" y2="12" />
                <line x1="3" y1="18" x2="21" y2="18" />
              </svg>
            </button>
          )}
          <button
            type="button"
            className={styles.backToTop}
            onClick={() => window.scrollTo({ top: 0, behavior: "smooth" })}
            aria-label="回到顶部"
          >
            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
              <path d="M18 15l-6-6-6 6" />
            </svg>
          </button>
        </>
      )}
    </>
  );
}
