import { useState, useRef, useEffect, useCallback } from "react";
import { Document, Page, pdfjs } from "react-pdf";
import "react-pdf/dist/Page/AnnotationLayer.css";
import "react-pdf/dist/Page/TextLayer.css";

pdfjs.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;

export default function PdfViewer({
  fileUrl,
  currentPage,
  onPageChange,
}: {
  fileUrl: string;
  currentPage?: number;
  onPageChange?: (page: number) => void;
}) {
  const [numPages, setNumPages] = useState(0);
  const [containerWidth, setContainerWidth] = useState(0);
  const containerRef = useRef<HTMLDivElement>(null);
  const scrollRef = useRef<HTMLDivElement>(null);
  const pageRefs = useRef<Map<number, HTMLDivElement>>(new Map());
  const [jumpPage, setJumpPage] = useState("");
  const programmaticScroll = useRef(false);

  // Resize observer for container width
  useEffect(() => {
    if (!containerRef.current) return;
    const observer = new ResizeObserver((entries) => {
      setContainerWidth(entries[0].contentRect.width);
    });
    observer.observe(containerRef.current);
    return () => observer.disconnect();
  }, []);

  // Scroll to page when currentPage changes (programmatic)
  useEffect(() => {
    if (!currentPage || currentPage < 1) return;
    const el = pageRefs.current.get(currentPage);
    if (el) {
      programmaticScroll.current = true;
      el.scrollIntoView({ behavior: "smooth", block: "start" });
      setTimeout(() => { programmaticScroll.current = false; }, 2000);
    }
  }, [currentPage]);

  // IntersectionObserver to detect visible page on user scroll
  useEffect(() => {
    if (numPages === 0 || !scrollRef.current) return;

    const visiblePages = new Map<number, number>();

    const observer = new IntersectionObserver(
      (entries) => {
        for (const entry of entries) {
          const pageNum = Number(entry.target.getAttribute("data-page"));
          if (entry.isIntersecting) {
            visiblePages.set(pageNum, entry.intersectionRatio);
          } else {
            visiblePages.delete(pageNum);
          }
        }

        // Don't fire callback during programmatic scroll
        if (programmaticScroll.current) return;

        // Find the page with the highest visibility ratio
        let bestPage = 0;
        let bestRatio = 0;
        for (const [page, ratio] of visiblePages) {
          if (ratio > bestRatio) {
            bestRatio = ratio;
            bestPage = page;
          }
        }
        if (bestPage > 0) {
          onPageChange?.(bestPage);
        }
      },
      {
        root: scrollRef.current,
        threshold: [0, 0.25, 0.5, 0.75, 1],
      },
    );

    for (const [, el] of pageRefs.current) {
      observer.observe(el);
    }

    return () => observer.disconnect();
  }, [numPages, onPageChange]);

  const setPageRef = useCallback((pageNum: number, el: HTMLDivElement | null) => {
    if (el) {
      el.setAttribute("data-page", String(pageNum));
      pageRefs.current.set(pageNum, el);
    } else {
      pageRefs.current.delete(pageNum);
    }
  }, []);

  const handleJump = () => {
    const p = parseInt(jumpPage, 10);
    if (p >= 1 && p <= numPages) {
      const el = pageRefs.current.get(p);
      el?.scrollIntoView({ behavior: "smooth", block: "start" });
    }
    setJumpPage("");
  };

  return (
    <div ref={containerRef} className="h-full flex flex-col bg-gray-100">
      {/* Page controls */}
      <div className="flex items-center justify-center gap-3 py-2 bg-white border-b border-gray-200 text-sm shrink-0">
        <span className="text-gray-600">
          {numPages} pages
        </span>
        <span className="text-gray-300">|</span>
        <span className="text-gray-600">
          Go to{" "}
          <input
            type="number"
            value={jumpPage}
            onChange={(e) => setJumpPage(e.target.value)}
            onKeyDown={(e) => { if (e.key === "Enter") handleJump(); }}
            placeholder="#"
            className="w-12 text-center border border-gray-300 rounded px-1 py-0.5 text-sm"
            min={1}
            max={numPages}
          />
        </span>
      </div>

      {/* All pages scrollable */}
      <div ref={scrollRef} className="flex-1 overflow-auto">
        <Document
          file={fileUrl}
          onLoadSuccess={({ numPages: n }) => setNumPages(n)}
          loading={
            <div className="flex items-center justify-center h-64 text-gray-400">
              Loading PDF...
            </div>
          }
          error={
            <div className="flex items-center justify-center h-64 text-red-400">
              Failed to load PDF
            </div>
          }
        >
          {numPages > 0 &&
            Array.from({ length: numPages }, (_, i) => i + 1).map((pageNum) => (
              <div
                key={pageNum}
                ref={(el) => setPageRef(pageNum, el)}
                className="flex justify-center mb-2"
              >
                <div className="bg-white shadow-sm">
                  <Page
                    pageNumber={pageNum}
                    width={containerWidth > 0 ? containerWidth - 48 : undefined}
                    renderAnnotationLayer
                    renderTextLayer
                  />
                </div>
              </div>
            ))}
        </Document>
      </div>
    </div>
  );
}
