import React, {
  useEffect,
  useRef,
  useState,
  useCallback,
  forwardRef,
  useImperativeHandle,
} from "react";

// Load external libraries
const loadExternalLibraries = (): Promise<void> => {
  return new Promise((resolve, reject) => {
    // Check if already loaded
    if ((window as any).pdfjsLib && (window as any).St) {
      resolve();
      return;
    }

    const scripts = [
      "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js",
      "https://unpkg.com/page-flip@2.0.7/dist/js/page-flip.browser.js",
    ];

    let loadedCount = 0;
    const totalScripts = scripts.length;

    scripts.forEach((src) => {
      const script = document.createElement("script");
      script.src = src;
      script.onload = () => {
        loadedCount++;
        if (loadedCount === totalScripts) {
          // Set PDF.js worker
          if ((window as any).pdfjsLib) {
            (window as any).pdfjsLib.GlobalWorkerOptions.workerSrc =
              "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js";
          }
          resolve();
        }
      };
      script.onerror = () => reject(new Error(`Failed to load ${src}`));
      document.head.appendChild(script);
    });
  });
};

export interface ReactPDFBookViewerProps {
  source?: string | File;
  width?: number;
  height?: number;
  onPageChange?: (page: number, total: number) => void;
  onLoadStart?: () => void;
  onLoadEnd?: () => void;
  onError?: (error: Error) => void;
  style?: React.CSSProperties;
  className?: string;
  loaderText?: string;
  loadingTextArray?: string[];
}

export interface PDFBookViewerMethods {
  load: (source: string | File) => Promise<void>;
  nextPage: () => void;
  prevPage: () => void;
  goToPage: (page: number) => void;
  destroy: () => void;
  getCurrentPage: () => number;
  getTotalPages: () => number;
}

export const ReactPDFBookViewer = forwardRef<
  PDFBookViewerMethods,
  ReactPDFBookViewerProps
>(
  (
    {
      source,
      width = 400,
      height = 600,
      onPageChange,
      onLoadStart,
      onLoadEnd,
      onError,
      style,
      className = "",
      loaderText = "Loading PDF...",
      loadingTextArray,
    },
    ref
  ) => {
    const containerRef = useRef<HTMLDivElement>(null);
    const [isLoading, setIsLoading] = useState(false);
    const [error, setError] = useState<string | null>(null);
    const [currentPage, setCurrentPage] = useState(0);
    const [totalPages, setTotalPages] = useState(0);

    // Store instances
    const instanceRef = useRef<{
      pdfDoc: any;
      pageFlip: any;
      pageImages: any[];
      pageElements: HTMLElement[];
    }>({
      pdfDoc: null,
      pageFlip: null,
      pageImages: [],
      pageElements: [],
    });

    const handleError = useCallback(
      (err: Error | string) => {
        const errorObj = err instanceof Error ? err : new Error(err);
        setError(errorObj.message);
        setIsLoading(false);
        onError?.(errorObj);
      },
      [onError]
    );

    // Convert PDF to images - exact copy from working JS
    const convertPDFToImages = useCallback(async (pdfDoc: any) => {
      const pageImages: any[] = [];

      for (let pageNum = 1; pageNum <= pdfDoc.numPages; pageNum++) {
        try {
          console.log(`Converting page ${pageNum} to image...`);

          const page = await pdfDoc.getPage(pageNum);
          const viewport = page.getViewport({ scale: 2 });

          const isLandscape = viewport.width > viewport.height;

          const canvas = document.createElement("canvas");
          const context = canvas.getContext("2d");
          canvas.height = viewport.height;
          canvas.width = viewport.width;

          if (context) {
            await page.render({
              canvasContext: context,
              viewport: viewport,
            }).promise;

            const imageUrl = canvas.toDataURL("image/jpeg", 0.9);

            if (isLandscape) {
              // Split landscape pages
              const leftImageUrl = cropImageLeft(canvas);
              const rightImageUrl = cropImageRight(canvas);

              pageImages.push({
                pdfPage: pageNum,
                side: "left",
                width: viewport.width / 2,
                height: viewport.height,
                isTransparent: false,
                imageUrl: leftImageUrl,
              });

              pageImages.push({
                pdfPage: pageNum,
                side: "right",
                width: viewport.width / 2,
                height: viewport.height,
                isTransparent: false,
                imageUrl: rightImageUrl,
              });
            } else {
              // Portrait page - handle differently based on position
              if (pageNum === pdfDoc.numPages) {
                // Last portrait page - show on left with transparent right
                pageImages.push({
                  pdfPage: pageNum,
                  side: "left",
                  width: viewport.width,
                  height: viewport.height,
                  isTransparent: false,
                  imageUrl: imageUrl,
                });

                pageImages.push({
                  pdfPage: pageNum,
                  side: "right",
                  width: viewport.width,
                  height: viewport.height,
                  isTransparent: true,
                  imageUrl: null,
                });
              } else {
                // First/middle portrait pages - show on right with transparent left
                pageImages.push({
                  pdfPage: pageNum,
                  side: "left",
                  width: viewport.width,
                  height: viewport.height,
                  isTransparent: true,
                  imageUrl: null,
                });

                pageImages.push({
                  pdfPage: pageNum,
                  side: "right",
                  width: viewport.width,
                  height: viewport.height,
                  isTransparent: false,
                  imageUrl: imageUrl,
                });
              }
            }
          }
        } catch (error) {
          console.error(`Error converting page ${pageNum}:`, error);
        }
      }

      return pageImages;
    }, []);

    const cropImageLeft = (canvas: HTMLCanvasElement) => {
      const cropCanvas = document.createElement("canvas");
      const cropCtx = cropCanvas.getContext("2d");
      const halfWidth = canvas.width / 2;

      cropCanvas.width = halfWidth;
      cropCanvas.height = canvas.height;

      if (cropCtx) {
        cropCtx.drawImage(
          canvas,
          0,
          0,
          halfWidth,
          canvas.height,
          0,
          0,
          halfWidth,
          canvas.height
        );
      }
      return cropCanvas.toDataURL("image/jpeg", 0.9);
    };

    const cropImageRight = (canvas: HTMLCanvasElement) => {
      const cropCanvas = document.createElement("canvas");
      const cropCtx = cropCanvas.getContext("2d");
      const halfWidth = canvas.width / 2;

      cropCanvas.width = halfWidth;
      cropCanvas.height = canvas.height;

      if (cropCtx) {
        cropCtx.drawImage(
          canvas,
          halfWidth,
          0,
          halfWidth,
          canvas.height,
          0,
          0,
          halfWidth,
          canvas.height
        );
      }
      return cropCanvas.toDataURL("image/jpeg", 0.9);
    };

    // Create page elements - exact copy from working JS
    const createPageElementsFromImages = useCallback((pageImages: any[]) => {
      const pageElements: HTMLElement[] = [];

      pageImages.forEach((pageImage) => {
        const pageDiv = document.createElement("div");
        pageDiv.className = "page";

        if (pageImage.isTransparent) {
          pageDiv.style.background = "none";
          pageDiv.style.backgroundColor = "transparent";
          pageDiv.style.opacity = "0";
        } else {
          pageDiv.style.backgroundColor = "white";
          pageDiv.style.opacity = "1";

          if (pageImage.imageUrl) {
            const img = document.createElement("img");
            img.src = pageImage.imageUrl;
            img.style.width = "100%";
            img.style.height = "100%";
            img.style.objectFit = "cover";
            img.style.display = "block";
            img.style.margin = "0";
            img.style.padding = "0";
            img.alt = `Page ${pageImage.pdfPage} ${pageImage.side}`;
            img.style.objectPosition = "center";

            img.onload = () => {
              console.log(
                `Image loaded for page ${pageImage.pdfPage} ${pageImage.side}`
              );
            };

            img.onerror = () => {
              console.error(
                `Failed to load image for page ${pageImage.pdfPage} ${pageImage.side}`
              );
            };

            pageDiv.appendChild(img);
          }
        }

        pageElements.push(pageDiv);
      });

      return pageElements;
    }, []);

    // Initialize PageFlip - exact copy from working JS
    const initializePageFlip = useCallback(
      (pageElements: HTMLElement[]) => {
        if (!containerRef.current) return;

        const St = (window as any).St;
        if (!St || !St.PageFlip) {
          console.error("PageFlip library not available");
          return;
        }

        // Clear container
        containerRef.current.innerHTML = "";

        // Initialize PageFlip with EXACT configuration from working JS
        const pageFlip = new St.PageFlip(containerRef.current, {
          width: width,
          height: height,
          size: "fixed",
          minWidth: width ? width : 315,
          maxWidth: 1000,
          minHeight: height ? height : 420,
          maxHeight: 1350,
          maxShadowOpacity: 0.5,
          showCover: false,
          mobileScrollSupport: false,
          swipeDistance: 30,
          clickEventForward: true,
          usePortrait: false,
          startPage: 0,
          drawShadow: true,
          flippingTime: 800,
          useMouseEvents: true,
          autoSize: false,
          showPageCorners: true,
          disableFlipByClick: false,
        });

        // Set up event listeners
        pageFlip.on("flip", (e: any) => {
          const newPage = e.data;
          setCurrentPage(newPage);
          const pdfPage = Math.floor(newPage / 2) + 1;
          onPageChange?.(pdfPage, totalPages);
        });

        pageFlip.on("changeOrientation", () => {
          console.log("Orientation changed");
        });

        pageFlip.on("changeState", (e: any) => {
          console.log("PageFlip state changed:", e.data);
        });

        // THIS IS THE CRUCIAL MISSING STEP!
        pageFlip.loadFromHTML(pageElements);

        instanceRef.current.pageFlip = pageFlip;
      },
      [onPageChange, totalPages]
    );

    // Load PDF - simplified and exact
    const loadPDF = useCallback(
      async (pdfSource: string | File) => {
        try {
          setIsLoading(true);
          setError(null);
          onLoadStart?.();

          await loadExternalLibraries();

          const pdfjsLib = (window as any).pdfjsLib;
          if (!pdfjsLib) {
            throw new Error("PDF.js not available");
          }

          let pdfDoc;
          if (typeof pdfSource === "string") {
            pdfDoc = await pdfjsLib.getDocument(pdfSource).promise;
          } else {
            const arrayBuffer = await pdfSource.arrayBuffer();
            pdfDoc = await pdfjsLib.getDocument({ data: arrayBuffer }).promise;
          }

          instanceRef.current.pdfDoc = pdfDoc;
          setTotalPages(pdfDoc.numPages);

          console.log(`PDF loaded: ${pdfDoc.numPages} pages`);

          // Convert PDF pages to images
          const pageImages = await convertPDFToImages(pdfDoc);
          instanceRef.current.pageImages = pageImages;

          // Create page elements from images
          const pageElements = createPageElementsFromImages(pageImages);
          instanceRef.current.pageElements = pageElements;

          // Initialize PageFlip
          initializePageFlip(pageElements);

          setIsLoading(false);
          onLoadEnd?.();
        } catch (err) {
          console.error("PDF loading error:", err);
          handleError(err as Error);
        }
      },
      [
        handleError,
        onLoadStart,
        onLoadEnd,
        convertPDFToImages,
        createPageElementsFromImages,
        initializePageFlip,
      ]
    );

    // Navigation methods
    const nextPage = useCallback(() => {
      if (instanceRef.current.pageFlip) {
        instanceRef.current.pageFlip.flipNext();
      }
    }, []);

    const prevPage = useCallback(() => {
      if (instanceRef.current.pageFlip) {
        instanceRef.current.pageFlip.flipPrev();
      }
    }, []);

    const goToPage = useCallback((pageNum: number) => {
      if (instanceRef.current.pageFlip) {
        const elementIndex = (pageNum - 1) * 2;
        instanceRef.current.pageFlip.flip(elementIndex);
      }
    }, []);

    // Load PDF when source changes
    useEffect(() => {
      if (source) {
        loadPDF(source);
      }
    }, [source, loadPDF]);

    // Expose methods via ref
    useImperativeHandle(
      ref,
      () => ({
        load: loadPDF,
        nextPage,
        prevPage,
        goToPage,
        destroy: () => {
          if (instanceRef.current.pageFlip) {
            instanceRef.current.pageFlip.destroy();
          }
          instanceRef.current = {
            pdfDoc: null,
            pageFlip: null,
            pageImages: [],
            pageElements: [],
          };
        },
        getCurrentPage: () => currentPage,
        getTotalPages: () => totalPages,
      }),
      [loadPDF, nextPage, prevPage, goToPage, currentPage, totalPages]
    );

    // Animated loading text (can be passed as prop)
    const defaultLoadingText = [
      "Loading PDF...",
      "Please wait while we prepare your book...",
      "Almost there!",
    ];
    const LoadingText =
      loadingTextArray && loadingTextArray.length > 0
        ? loadingTextArray
        : defaultLoadingText;
    const [loadingTextIndex, setLoadingTextIndex] = useState(0);

    useEffect(() => {
      if (isLoading) {
        setLoadingTextIndex(0);
        const interval = setInterval(() => {
          setLoadingTextIndex((prev) => (prev + 1) % LoadingText.length);
        }, 3500);
        return () => clearInterval(interval);
      }
    }, [isLoading]);

    if (isLoading) {
      return (
        <div style={{ textAlign: "center", padding: "40px" }}>
          <div
            style={{
              display: "flex",
              flexDirection: "column",
              alignItems: "center",
              gap: "18px",
            }}
          >
            <div
              style={{
                width: 48,
                height: 48,
                border: "6px solid #eee",
                borderTop: "6px solid #f60",
                borderRadius: "50%",
                animation: "pdfbook-spin 1s linear infinite",
              }}
            />
            <div>{LoadingText[loadingTextIndex]}</div>
          </div>
          <style>{`
            @keyframes pdfbook-spin {
              0% { transform: rotate(0deg); }
              100% { transform: rotate(360deg); }
            }
          `}</style>
        </div>
      );
    }

    if (error) {
      return (
        <div style={{ textAlign: "center", padding: "40px", color: "red" }}>
          <div>Error: {error}</div>
        </div>
      );
    }

    return (
      <div className={className} style={style}>
        <div
          ref={containerRef}
          style={{
            width: `${width}px`,
            height: `${height}px`,
            margin: "0 auto",
          }}
        />
      </div>
    );
  }
);

ReactPDFBookViewer.displayName = "ReactPDFBookViewer";

export default ReactPDFBookViewer;
