// PDF navigation: page turning, zoom, fit modes
// Feature Registration Pattern implementation

import type { ReaderContext } from "../core/reader-context";

export function init(context: ReaderContext): void {
  let navState: PDFNavigationState | null = null;

  context.events.on("reader:loaded", (detail: { container: HTMLElement; totalPages: number }) => {
    navState = {
      currentPage: 1,
      totalPages: detail.totalPages,
      currentScale: 1.0,
      fitMode: "fit-width",
      scrollContainer: detail.container.querySelector(".pdf-scroll-container") || detail.container,
    };
    setupPDFKeyboardNav(context, navState);
    setupPDFScrollTracking(context, navState);
  });

  context.events.on("pdf:navigate:to-page", (detail: { page: number }) => {
    if (navState) {
      goToPDFPage(navState, detail.page, context);
    }
  });

  context.events.on("pdf:navigate:next", () => {
    if (navState) {
      nextPDFPage(navState, context);
    }
  });

  context.events.on("pdf:navigate:previous", () => {
    if (navState) {
      previousPDFPage(navState, context);
    }
  });

  context.events.on("pdf:zoom:set", (detail: { scale: number }) => {
    if (navState) {
      setPDFZoom(navState, detail.scale, context);
    }
  });

  context.events.on("pdf:zoom:in", () => {
    if (navState) {
      zoomPDFIn(navState, context);
    }
  });

  context.events.on("pdf:zoom:out", () => {
    if (navState) {
      zoomPDFOut(navState, context);
    }
  });

  context.events.on("pdf:fit:set", (detail: { mode: "fit-width" | "fit-page" | "fit-height" | "none" }) => {
    if (navState) {
      setPDFFitMode(navState, detail.mode, context);
    }
  });

  context.events.on("reader:unload", () => {
    navState = null;
  });
}

type PageFitMode = "fit-width" | "fit-page" | "fit-height" | "none";

interface PDFNavigationState {
  currentPage: number;
  totalPages: number;
  currentScale: number;
  fitMode: PageFitMode;
  scrollContainer: HTMLElement | null;
}

function goToPDFPage(state: PDFNavigationState, pageNumber: number, context: ReaderContext): void {
  if (pageNumber < 1 || pageNumber > state.totalPages) return;

  state.currentPage = pageNumber;
  scrollToPDFPage(state, pageNumber);
  context.events.emit("pdf:page-changed", { page: pageNumber });
}

function nextPDFPage(state: PDFNavigationState, context: ReaderContext): void {
  if (state.currentPage < state.totalPages) {
    goToPDFPage(state, state.currentPage + 1, context);
  }
}

function previousPDFPage(state: PDFNavigationState, context: ReaderContext): void {
  if (state.currentPage > 1) {
    goToPDFPage(state, state.currentPage - 1, context);
  }
}

function scrollToPDFPage(state: PDFNavigationState, pageNumber: number): void {
  if (!state.scrollContainer) return;

  const pageElement = state.scrollContainer.querySelector(
    `[data-page-number="${pageNumber}"]`,
  );
  if (pageElement) {
    pageElement.scrollIntoView({ behavior: "smooth", block: "start" });
  }
}

function setPDFZoom(state: PDFNavigationState, scale: number, context: ReaderContext): void {
  state.currentScale = scale;
  state.fitMode = "none";
  updatePDFZoom(state);
  context.events.emit("pdf:zoom-changed", { scale });
}

function setPDFFitMode(state: PDFNavigationState, mode: PageFitMode, context: ReaderContext): void {
  state.fitMode = mode;
  updatePDFZoom(state);
  context.events.emit("pdf:fit-changed", { mode });
}

function zoomPDFIn(state: PDFNavigationState, context: ReaderContext): void {
  setPDFZoom(state, state.currentScale * 1.2, context);
}

function zoomPDFOut(state: PDFNavigationState, context: ReaderContext): void {
  setPDFZoom(state, state.currentScale / 1.2, context);
}

function updatePDFZoom(state: PDFNavigationState): void {
  const event = new CustomEvent("pdf-update-zoom", {
    detail: {
      scale: state.currentScale,
      fitMode: state.fitMode,
    },
  });
  window.dispatchEvent(event);
}

function setupPDFKeyboardNav(context: ReaderContext, state: PDFNavigationState): void {
  document.addEventListener("keydown", (e) => {
    if (e.key === "ArrowRight" || e.key === "ArrowDown") {
      nextPDFPage(state, context);
    } else if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
      previousPDFPage(state, context);
    } else if (e.key === "+" || e.key === "=") {
      zoomPDFIn(state, context);
    } else if (e.key === "-" || e.key === "_") {
      zoomPDFOut(state, context);
    }
  });
}

function setupPDFScrollTracking(context: ReaderContext, state: PDFNavigationState): void {
  if (!state.scrollContainer) return;

  state.scrollContainer.addEventListener("scroll", () => {
    const currentPage = getCurrentPDFPage(state);
    if (currentPage !== state.currentPage) {
      state.currentPage = currentPage;
      context.events.emit("pdf:page-changed", { page: currentPage });
    }
  });
}

function getCurrentPDFPage(state: PDFNavigationState): number {
  if (!state.scrollContainer) return state.currentPage;

  const containerRect = state.scrollContainer.getBoundingClientRect();
  const viewportMiddle = containerRect.top + containerRect.height / 2;

  for (let i = 1; i <= state.totalPages; i++) {
    const pageElement = state.scrollContainer.querySelector(
      `[data-page-number="${i}"]`,
    );
    if (pageElement) {
      const rect = pageElement.getBoundingClientRect();
      if (rect.top <= viewportMiddle && rect.bottom >= viewportMiddle) {
        return i;
      }
    }
  }

  return state.currentPage;
}