"use client";

import { useEffect, useState, useRef, useCallback } from "react";
import Link from "next/link";
import type { EbookData } from "@/app/lib/ebook";
import "github-markdown-css/github-markdown.css";
import styles from "./ebook.module.css";

function LazyChunk({
  html,
  estimatedHeight,
  forceVisible,
}: {
  html: string;
  estimatedHeight: number;
  forceVisible: boolean;
}) {
  const [visible, setVisible] = useState(forceVisible);
  const ref = useRef<HTMLDivElement>(null);
  const show = forceVisible || visible;

  useEffect(() => {
    if (forceVisible || visible) return;
    const el = ref.current;
    if (!el) return;
    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          setVisible(true);
          observer.disconnect();
        }
      },
      { rootMargin: "1200px 0px" }
    );
    observer.observe(el);
    return () => observer.disconnect();
  }, [forceVisible, visible]);

  if (show) {
    return (
      <div
        className={`${styles.chunkEnter} animate__animated animate__fadeInUp`}
        style={{ animationDuration: "0.5s", animationFillMode: "both" }}
        dangerouslySetInnerHTML={{ __html: html }}
      />
    );
  }
  return (
    <div
      ref={ref}
      className={styles.chunkPlaceholder}
      style={{ minHeight: estimatedHeight }}
    />
  );
}

export default function EbookClient({
  data,
  title = "数字游民",
  backHref = "/",
}: {
  data: EbookData;
  title?: string;
  backHref?: string;
}) {
  const [showDrawer, setShowDrawer] = useState(false);
  const [readProgress, setReadProgress] = useState(0);
  const [showBackTop, setShowBackTop] = useState(false);
  const [forceShowAll, setForceShowAll] = useState(false);
  const contentRef = useRef<HTMLDivElement>(null);

  const { chunks, headers } = data;

  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 > 600);
        ticking = false;
      });
    };
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  const handleJump = useCallback(
    (index: number) => {
      setForceShowAll(true);
      setShowDrawer(false);

      const run = () => {
        const root = contentRef.current;
        if (!root) return;
        const h1s = root.querySelectorAll("h1");
        const h2s = root.querySelectorAll("h2");
        const targets = h1s.length > 0 ? h1s : h2s;
        const el = targets[index] as HTMLElement;
        if (el) {
          try {
            el.scrollIntoView({ behavior: "smooth", block: "start" });
          } catch {
            const top =
              el.getBoundingClientRect().top +
              (window.pageYOffset || document.documentElement.scrollTop) -
              60;
            window.scrollTo({ top: Math.max(0, top), behavior: "smooth" });
          }
        }
      };

      run();
      setTimeout(run, 100);
      setTimeout(run, 300);
      setTimeout(run, 600);
    },
    []
  );

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

      <div className={styles.headerSpacer} />
      <header className={`${styles.header} animate__animated animate__fadeInDown`} style={{ animationFillMode: "both" }}>
        <Link href={backHref} className={styles.headerLeft} aria-label="返回首页">
          <svg
            width="24"
            height="24"
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            strokeWidth="2"
          >
            <path d="M15 18l-6-6 6-6" />
          </svg>
        </Link>
        <div className={styles.headerMiddle}>{title}</div>
        <button
          type="button"
          className={`${styles.headerRight} ${showDrawer ? styles.headerRightActive : ""}`}
          onClick={() => setShowDrawer(!showDrawer)}
          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>
          <span className={styles.headerRightText}>目录</span>
        </button>
      </header>

      <div className={styles.book}>
        <div ref={contentRef} className={`markdown-body ${styles.markdownBody}`}>
          {chunks.map((chunk, i) => (
            <LazyChunk
              key={i}
              html={chunk.html}
              estimatedHeight={chunk.estimatedHeight}
              forceVisible={forceShowAll || i === 0}
            />
          ))}
        </div>
      </div>

      <div
        className={`${styles.drawerMask} ${showDrawer ? styles.drawerMaskOpen : ""}`}
        onClick={() => setShowDrawer(false)}
        aria-hidden="true"
      />
      <aside
        className={`${styles.drawer} ${showDrawer ? styles.drawerOpen : ""}`}
      >
        {headers.map((titleItem, index) => (
          <div
            key={index}
            role="button"
            tabIndex={0}
            className={styles.drawerItem}
            onClick={() => handleJump(index)}
            onKeyDown={(e) => {
              if (e.key === "Enter" || e.key === " ") handleJump(index);
            }}
          >
            {titleItem}
          </div>
        ))}
      </aside>

      {showBackTop && (
        <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>
      )}
    </>
  );
}
