// 5-page ahead cache for PDF pages
// Pre-renders canvas and text layer for nearby pages

import { PDFPageProxy, PageViewport } from "pdfjs-dist";

interface CachedPage {
  pageNumber: number;
  canvas: HTMLCanvasElement;
  textLayer: HTMLElement;
  viewport: PageViewport;
  timestamp: number;
}

// 5-page ahead cache for PDF pages
// Procedural implementation (no OOP)

interface CachedPage {
  pageNumber: number;
  canvas: HTMLCanvasElement;
  textLayer: HTMLElement;
  viewport: PageViewport;
  timestamp: number;
}

interface PDFPageCacheState {
  cache: Map<number, CachedPage>;
  maxCacheSize: number;
  renderCallbacks: Map<number, Array<() => void>>;
}

function createPDFPageCache(maxCacheSize: number = 5): PDFPageCacheState {
  return {
    cache: new Map(),
    maxCacheSize,
    renderCallbacks: new Map(),
  };
}

async function getCachedPage(
  state: PDFPageCacheState,
  pageNumber: number,
  renderFn: (
    pageNumber: number,
  ) => Promise<{
    canvas: HTMLCanvasElement;
    textLayer: HTMLElement;
    viewport: PageViewport;
  }>,
): Promise<PDFPageCacheState & { page: CachedPage }> {
  const cached = state.cache.get(pageNumber);
  if (cached) {
    cached.timestamp = Date.now();
    return { ...state, page: cached };
  }

  const { canvas, textLayer, viewport } = await renderFn(pageNumber);

  const cachedPage: CachedPage = {
    pageNumber,
    canvas,
    textLayer,
    viewport,
    timestamp: Date.now(),
  };

  const newCache = new Map(state.cache);
  newCache.set(pageNumber, cachedPage);

  const callbacks = state.renderCallbacks.get(pageNumber);
  if (callbacks) {
    callbacks.forEach((cb) => cb());
    const newCallbacks = new Map(state.renderCallbacks);
    newCallbacks.delete(pageNumber);
    return {
      ...state,
      cache: newCache,
      renderCallbacks: newCallbacks,
      page: cachedPage,
    };
  }

  return { ...state, cache: newCache, page: cachedPage };
}

function preloadPages(
  state: PDFPageCacheState,
  currentPage: number,
  totalPages: number,
): PDFPageCacheState {
  for (let i = 1; i <= state.maxCacheSize; i++) {
    const pageNumber = currentPage + i;
    if (pageNumber <= totalPages && !state.cache.has(pageNumber)) {
      triggerPreload(pageNumber);
    }
  }

  return state;
}

function triggerPreload(pageNumber: number): void {
  console.log("Preloading page:", pageNumber);
}

function invalidatePage(
  state: PDFPageCacheState,
  pageNumber: number,
): PDFPageCacheState {
  const cached = state.cache.get(pageNumber);
  if (cached) {
    cached.canvas.remove();
    cached.textLayer.remove();

    const newCache = new Map(state.cache);
    newCache.delete(pageNumber);

    return { ...state, cache: newCache };
  }

  return state;
}

function clearPageCache(state: PDFPageCacheState): PDFPageCacheState {
  state.cache.forEach((page) => {
    page.canvas.remove();
    page.textLayer.remove();
  });

  return {
    ...state,
    cache: new Map(),
  };
}

function onPageRendered(
  state: PDFPageCacheState,
  pageNumber: number,
  callback: () => void,
): PDFPageCacheState {
  const newCallbacks = new Map(state.renderCallbacks);

  if (!newCallbacks.has(pageNumber)) {
    newCallbacks.set(pageNumber, []);
  }

  newCallbacks.get(pageNumber)!.push(callback);

  return { ...state, renderCallbacks: newCallbacks };
}
