"use client";

import { useState, useEffect, useRef, useCallback } from "react";
import Link from "next/link";
import { useRouter } from "next/navigation";

type ChapterMeta = {
  id: number;
  number: number;
  title: string;
  totalPages: number;
};

type LoadedPage = {
  chapterNumber: number;
  pageNumber: number;
  imageUrl: string;
};

type RawPage = {
  number: number;
  imageUrl: string;
};

type PageReaderProps = {
  mangaSlug: string;
  mangaTitle: string;
  startChapterNumber: number;
  prevChapter: number | null;
  nextChapter: number | null;
  chapters: ChapterMeta[];
};

const BATCH_SIZE = 7;
const PREFETCH_AT = 3;

export function PageReader({
  mangaSlug,
  mangaTitle,
  startChapterNumber,
  prevChapter,
  nextChapter,
  chapters,
}: PageReaderProps) {
  const [showUI, setShowUI] = useState(true);
  const [showDrawer, setShowDrawer] = useState(false);
  const [pages, setPages] = useState<LoadedPage[]>([]);
  const [currentChapterNum, setCurrentChapterNum] =
    useState(startChapterNumber);

  const hiddenByScrollRef = useRef(false);
  const fetchChapterIdxRef = useRef(
    chapters.findIndex((c) => c.number === startChapterNumber)
  );
  const offsetRef = useRef(0);
  const loadingRef = useRef(false);
  const doneRef = useRef(false);
  // Count of pages already loaded — tracked via ref so fetchBatch stays stable
  // (otherwise every batch re-creates fetchBatch and tears down the observer)
  const loadedCountRef = useRef(0);
  const triggerIndicesRef = useRef<Set<number>>(new Set());
  const observerRef = useRef<IntersectionObserver | null>(null);
  const pageRefsRef = useRef<Map<number, HTMLDivElement>>(new Map());

  const advanceChapterOrFinish = useCallback(() => {
    if (fetchChapterIdxRef.current + 1 < chapters.length) {
      fetchChapterIdxRef.current += 1;
      offsetRef.current = 0;
    } else {
      doneRef.current = true;
    }
  }, [chapters.length]);

  const fetchBatch = useCallback(async () => {
    if (loadingRef.current || doneRef.current) return;
    const chapter = chapters[fetchChapterIdxRef.current];
    if (!chapter) {
      doneRef.current = true;
      return;
    }
    loadingRef.current = true;
    try {
      const res = await fetch(
        `/api/pages?chapterId=${chapter.id}&offset=${offsetRef.current}&limit=${BATCH_SIZE}`
      );
      const batch: RawPage[] = await res.json();
      if (batch.length === 0) {
        advanceChapterOrFinish();
        return;
      }

      const baseIndex = loadedCountRef.current;
      const willHaveMore =
        offsetRef.current + batch.length < chapter.totalPages ||
        fetchChapterIdxRef.current + 1 < chapters.length;
      if (willHaveMore) {
        const triggerIndex = baseIndex + PREFETCH_AT - 1;
        triggerIndicesRef.current.add(triggerIndex);
        const existing = pageRefsRef.current.get(triggerIndex);
        if (existing && observerRef.current) {
          observerRef.current.observe(existing);
        }
      }

      loadedCountRef.current += batch.length;
      setPages((prev) => [
        ...prev,
        ...batch.map((p) => ({
          chapterNumber: chapter.number,
          pageNumber: p.number,
          imageUrl: p.imageUrl,
        })),
      ]);
      offsetRef.current += batch.length;
      if (offsetRef.current >= chapter.totalPages) {
        advanceChapterOrFinish();
      }
    } catch {
      // retry on next intersection
    } finally {
      loadingRef.current = false;
    }
  }, [chapters, advanceChapterOrFinish]);

  useEffect(() => {
    observerRef.current = new IntersectionObserver(
      (entries) => {
        for (const entry of entries) {
          if (entry.isIntersecting) {
            const index = Number(
              (entry.target as HTMLElement).dataset.pageIndex
            );
            if (triggerIndicesRef.current.has(index)) {
              triggerIndicesRef.current.delete(index);
              fetchBatch();
            }
          }
        }
      },
      { rootMargin: "400px" }
    );
    return () => observerRef.current?.disconnect();
  }, [fetchBatch]);

  const initialFetchRef = useRef(false);
  useEffect(() => {
    if (initialFetchRef.current) return;
    initialFetchRef.current = true;
    fetchBatch();
  }, [fetchBatch]);

  const setPageRef = useCallback(
    (index: number, el: HTMLDivElement | null) => {
      const observer = observerRef.current;
      if (!observer) return;
      const prev = pageRefsRef.current.get(index);
      if (prev) observer.unobserve(prev);
      if (el) {
        pageRefsRef.current.set(index, el);
        if (triggerIndicesRef.current.has(index)) {
          observer.observe(el);
        }
      } else {
        pageRefsRef.current.delete(index);
      }
    },
    []
  );

  const router = useRouter();

  const touchMovedRef = useRef(false);
  // Pending single-tap toggle, delayed so we can detect a double-tap first
  const singleTapTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const lastTapAtRef = useRef(0);
  const DOUBLE_TAP_MS = 280;

  const onTouchStart = useCallback(() => {
    touchMovedRef.current = false;
  }, []);
  const onTouchMove = useCallback(() => {
    touchMovedRef.current = true;
  }, []);

  const onTap = useCallback(
    (e: React.MouseEvent) => {
      if (touchMovedRef.current) return;
      const now = Date.now();
      const isDoubleTap = now - lastTapAtRef.current < DOUBLE_TAP_MS;

      if (isDoubleTap) {
        // Cancel pending single-tap, navigate instead
        if (singleTapTimerRef.current) {
          clearTimeout(singleTapTimerRef.current);
          singleTapTimerRef.current = null;
        }
        lastTapAtRef.current = 0;
        const midX = window.innerWidth / 2;
        if (e.clientX >= midX) {
          if (nextChapter)
            router.push(`/manga/${mangaSlug}/${nextChapter}`);
        } else {
          if (prevChapter)
            router.push(`/manga/${mangaSlug}/${prevChapter}`);
        }
        return;
      }

      lastTapAtRef.current = now;
      singleTapTimerRef.current = setTimeout(() => {
        setShowUI((v) => !v);
        singleTapTimerRef.current = null;
      }, DOUBLE_TAP_MS);
    },
    [router, mangaSlug, nextChapter, prevChapter]
  );

  useEffect(
    () => () => {
      if (singleTapTimerRef.current) clearTimeout(singleTapTimerRef.current);
    },
    []
  );

  useEffect(() => {
    let rafId = 0;
    const tick = () => {
      rafId = 0;
      const y = window.scrollY;
      if (!hiddenByScrollRef.current && y > 50) {
        hiddenByScrollRef.current = true;
        setShowUI(false);
      }
      let current = startChapterNumber;
      for (let i = 0; i < pages.length; i++) {
        const el = pageRefsRef.current.get(i);
        if (!el) continue;
        if (el.offsetTop <= y + 80) current = pages[i].chapterNumber;
        else break;
      }
      setCurrentChapterNum(current);
    };
    const onScroll = () => {
      if (rafId) return;
      rafId = requestAnimationFrame(tick);
    };
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => {
      window.removeEventListener("scroll", onScroll);
      if (rafId) cancelAnimationFrame(rafId);
    };
  }, [pages, startChapterNumber]);

  const currentChapter =
    chapters.find((c) => c.number === currentChapterNum) ??
    chapters.find((c) => c.number === startChapterNumber);

  return (
    <div className="min-h-dvh bg-background">
      <div
        className={`sticky top-0 z-50 bg-background backdrop-blur-sm shadow-sm transition-transform duration-300 pt-safe ${
          showUI ? "translate-y-0" : "-translate-y-full"
        }`}
      >
        <div className="flex items-center gap-3 px-4 h-12 max-w-4xl mx-auto">
          <Link
            href={`/manga/${mangaSlug}`}
            className="text-foreground/80 hover:text-foreground transition-colors shrink-0"
            aria-label="Back to manga"
          >
            <svg
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              strokeWidth={2}
              className="w-6 h-6"
            >
              <polyline points="15 18 9 12 15 6" />
            </svg>
          </Link>
          <div className="min-w-0 flex-1">
            <p className="text-foreground text-sm font-medium truncate">
              {mangaTitle}
            </p>
            <p className="text-muted text-xs truncate">
              Ch. {currentChapter?.number} — {currentChapter?.title}
            </p>
          </div>
          <button
            onClick={() => setShowDrawer(true)}
            className="text-foreground/80 hover:text-foreground transition-colors shrink-0"
            aria-label="Chapter list"
          >
            <svg
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              strokeWidth={2}
              className="w-6 h-6"
            >
              <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>
        </div>
      </div>

      <div
        className="max-w-4xl mx-auto leading-[0] select-none"
        onClick={onTap}
        onTouchStart={onTouchStart}
        onTouchMove={onTouchMove}
        onContextMenu={(e) => e.preventDefault()}
      >
        {pages.map((page, i) => {
          const isChapterStart =
            i === 0 || pages[i - 1].chapterNumber !== page.chapterNumber;
          return (
            <div
              key={`${page.chapterNumber}-${page.pageNumber}`}
              className="relative leading-[0]"
              data-page-index={i}
              ref={(el) => setPageRef(i, el)}
            >
              {isChapterStart && i > 0 && (
                <div className="bg-surface py-4 text-center leading-normal">
                  <p className="text-xs uppercase tracking-wider text-muted">
                    Chapter {page.chapterNumber}
                  </p>
                  <p className="text-sm font-semibold text-foreground">
                    {
                      chapters.find((c) => c.number === page.chapterNumber)
                        ?.title
                    }
                  </p>
                </div>
              )}
              <img
                src={page.imageUrl}
                alt={`Page ${page.pageNumber}`}
                className="w-full h-auto block align-bottom -mb-px [-webkit-touch-callout:none]"
                draggable={false}
              />
            </div>
          );
        })}
      </div>

      {doneRef.current && pages.length > 0 && (
        <div className="min-h-dvh max-w-4xl mx-auto px-4 flex flex-col items-center justify-center text-center leading-normal gap-4">
          <p className="text-xs uppercase tracking-wider text-muted">
            End of Manga
          </p>
          <p className="text-base font-semibold">{mangaTitle}</p>
          <Link
            href={`/manga/${mangaSlug}`}
            className="px-5 py-2 rounded-lg bg-accent text-white text-sm font-semibold transition-colors hover:bg-accent-hover"
          >
            Back to Manga
          </Link>
        </div>
      )}

      {/* Chapter drawer overlay (modal — fixed is necessary to cover viewport) */}
      {showDrawer && (
        <div
          className="fixed inset-0 z-[60]"
          onClick={() => setShowDrawer(false)}
        >
          <div className="absolute inset-0 bg-black/50 backdrop-blur-sm" />
          <div
            className="absolute bottom-0 left-0 right-0 max-h-[75vh] bg-background rounded-t-3xl shadow-2xl overflow-hidden"
            onClick={(e) => e.stopPropagation()}
          >
            <div className="sticky top-0 bg-background z-10 border-b border-border">
              <div className="flex justify-center pt-2.5 pb-1.5">
                <div className="w-10 h-1 rounded-full bg-muted/40" />
              </div>
              <div className="px-5 py-3 flex items-center justify-between">
                <span className="text-foreground text-base font-bold">
                  Chapters
                </span>
                <span className="text-xs text-muted tabular-nums">
                  {chapters.length} total
                </span>
              </div>
            </div>
            <div className="overflow-y-auto max-h-[calc(75vh-4rem)] pb-safe">
              {chapters.map((ch) => {
                const isActive = ch.number === currentChapterNum;
                return (
                  <Link
                    key={ch.number}
                    href={`/manga/${mangaSlug}/${ch.number}`}
                    className={`flex items-center gap-3 px-5 py-3 text-sm transition-colors ${
                      isActive
                        ? "bg-accent/10"
                        : "hover:bg-surface active:bg-surface-hover"
                    }`}
                    onClick={() => setShowDrawer(false)}
                  >
                    <span
                      className={`font-bold tabular-nums w-10 shrink-0 ${
                        isActive ? "text-accent" : "text-muted"
                      }`}
                    >
                      #{ch.number}
                    </span>
                    <span
                      className={`truncate ${
                        isActive
                          ? "text-accent font-semibold"
                          : "text-foreground"
                      }`}
                    >
                      {ch.title}
                    </span>
                    {isActive && (
                      <span className="ml-auto shrink-0 text-[10px] uppercase tracking-wider font-bold text-accent">
                        Current
                      </span>
                    )}
                  </Link>
                );
              })}
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
