import React, {
  useCallback,
  useContext,
  useMemo,
  useRef,
  useState,
} from 'react';

import { type PdfDimensionsMetadata } from 'src/pages/dashboard/serviceManagement/types';

import {
  HEADER_HEIGHT,
  MAX_ZOOM_SCALE,
  MIN_ZOOM_SCALE,
  PDF_VIEWER_TOP_PADDING,
} from '../../../constants';

type PdfCompletionContextType = {
  currentPage: number;
  handlePageChange: (currentPage: number) => void;
  setCurrentPageInView: (currentPage: number) => void;
  totalPages: number;
  scale: number;
  handleZoomIn: () => void;
  handleZoomOut: () => void;
  scrollContainerRef: React.RefObject<HTMLDivElement>;
  registerPageRef: (index: number, el: HTMLDivElement | null) => void;
  scrollToPage: (page: number, behavior?: ScrollBehavior) => void;
  // Scroll to a Y position inside a specific page (yRelative is 0..1 in page coords)
  scrollToFieldPosition: (
    page: number,
    yRelative: number,
    behavior?: ScrollBehavior,
  ) => void;
  // Height of any sticky/overlay UI above the scroll container (e.g. paginator)
  topOverlayOffset: number;
  setTopOverlayOffset: (px: number) => void;
  setPdfDimensionsMetadata: (
    pdfDimensionsMetadata: PdfDimensionsMetadata,
  ) => void;
  pdfDimensionsMetadata: PdfDimensionsMetadata | null;
  showErrors: boolean;
  setShowErrors: (showErrors: boolean) => void;
};

const PdfCompletionContext =
  React.createContext<PdfCompletionContextType | null>(null);

export const usePdfCompletion = () => {
  return useContext(PdfCompletionContext) as PdfCompletionContextType;
};

const PdfCompletionProvider = ({ children }: { children: JSX.Element }) => {
  const [pdfDimensionsMetadata, setPdfDimensionsMetadata] =
    useState<PdfDimensionsMetadata | null>(null);
  const [currentPage, setCurrentPage] = useState(1);
  const [showErrors, setShowErrors] = useState(false);
  const [scale, setScale] = useState(1);
  const [topOverlayOffset, setTopOverlayOffset] = useState(0);
  const scrollContainerRef = useRef<HTMLDivElement | null>(null);
  const pageRefs = useRef<(HTMLDivElement | null)[]>([]);

  const setCurrentPageInView = useCallback((page: number) => {
    setCurrentPage(page);
  }, []);

  const registerPageRef = useCallback(
    (index: number, el: HTMLDivElement | null) => {
      pageRefs.current[index] = el;
    },
    [],
  );

  const scrollToPage = useCallback(
    (page: number, behavior: ScrollBehavior = 'smooth') => {
      const container = scrollContainerRef.current;
      const target = pageRefs.current[page - 1];
      if (!container || !target) return;

      const baseTop = target.offsetTop;
      // Align page top with the container's top, compensating any sticky overlay inside the container
      const offset = Math.max(topOverlayOffset, 0);
      const top = Math.max(baseTop - offset, 0);
      container.scrollTo({
        top: top - HEADER_HEIGHT - PDF_VIEWER_TOP_PADDING,
        behavior,
      });
    },
    [topOverlayOffset],
  );

  const scrollToFieldPosition = useCallback(
    (page: number, yRelative: number, behavior: ScrollBehavior = 'smooth') => {
      const container = scrollContainerRef.current;
      const pageEl = pageRefs.current[page - 1];
      if (!container || !pageEl) return;

      const r = Math.max(0, Math.min(1, yRelative));
      const offsetInsidePage = r * pageEl.offsetHeight;
      const absoluteTop = pageEl.offsetTop + offsetInsidePage;
      // If already in (effective) view, skip scrolling
      const viewportTop = container.scrollTop + topOverlayOffset;
      const viewportBottom = container.scrollTop + container.clientHeight;
      const tolerance = 8; // px margin to avoid micro scrolls
      if (
        absoluteTop >= viewportTop + tolerance &&
        absoluteTop <= viewportBottom - tolerance
      ) {
        return;
      }

      // Header height + extra margin
      const offset = topOverlayOffset + HEADER_HEIGHT + tolerance;
      const top = Math.max(absoluteTop - offset, 0);
      container.scrollTo({ top, behavior });
    },
    [topOverlayOffset],
  );

  const handlePageChange = useCallback(
    (page: number) => {
      setCurrentPage(page);
      scrollToPage(page);
    },
    [scrollToPage],
  );

  const handleZoomIn = useCallback(
    () => setScale(s => Math.min(s + 0.1, MAX_ZOOM_SCALE)),
    [],
  );
  const handleZoomOut = useCallback(
    () => setScale(s => Math.max(s - 0.1, MIN_ZOOM_SCALE)),
    [],
  );

  const totalPages = pdfDimensionsMetadata?.totalPages || 0;

  const value = useMemo(
    () => ({
      currentPage,
      handlePageChange,
      setCurrentPageInView,
      handleZoomIn,
      handleZoomOut,
      totalPages,
      scale,
      scrollContainerRef,
      registerPageRef,
      scrollToPage,
      scrollToFieldPosition,
      topOverlayOffset,
      setTopOverlayOffset,
      setPdfDimensionsMetadata,
      pdfDimensionsMetadata,
      showErrors,
      setShowErrors,
    }),
    [
      currentPage,
      handlePageChange,
      setCurrentPageInView,
      handleZoomIn,
      handleZoomOut,
      totalPages,
      scale,
      registerPageRef,
      scrollToPage,
      scrollToFieldPosition,
      topOverlayOffset,
      pdfDimensionsMetadata,
      showErrors,
    ],
  );

  return (
    <PdfCompletionContext.Provider value={value}>
      {children}
    </PdfCompletionContext.Provider>
  );
};

export default PdfCompletionProvider;
