// Vertical scroll mode for webtoons/manhwa
// Feature Registration Pattern implementation

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

export function init(context: ReaderContext): void {
  let state: VerticalScrollState | null = null;

  context.events.on("reader:loaded", (detail: { container: HTMLElement; mediaItemId: string; totalPages: number }) => {
    state = createVerticalScroll(detail.container, detail.mediaItemId, detail.totalPages);
  });

  context.events.on("vertical-scroll:load-page", async (detail: { pageNumber: number }) => {
    if (state) {
      await loadPage(state, detail.pageNumber);
    }
  });

  context.events.on("vertical-scroll:get-current", () => {
    if (state) {
      const currentPage = getCurrentPageFromScroll(state);
      context.events.emit("vertical-scroll:current-page", { page: currentPage });
    }
  });

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

interface VerticalScrollState {
  container: HTMLElement;
  loadedPages: Set<number>;
  loadingPages: Set<number>;
  currentPage: number;
  totalPages: number;
  threshold: number;
  mediaItemId: string;
}

function createVerticalScroll(
  container: HTMLElement,
  mediaItemId: string,
  totalPages: number,
): VerticalScrollState {
  const state: VerticalScrollState = {
    container,
    loadedPages: new Set(),
    loadingPages: new Set(),
    currentPage: 1,
    totalPages,
    threshold: 500,
    mediaItemId,
  };

  loadPage(state, 1);
  setupScrollListener(state);

  return state;
}

async function loadPage(
  state: VerticalScrollState,
  pageNumber: number,
): Promise<void> {
  if (state.loadedPages.has(pageNumber) || state.loadingPages.has(pageNumber)) {
    return;
  }

  state.loadingPages.add(pageNumber);

  try {
    const token = localStorage.getItem("token");
    const response = await fetch(
      `/readers/${state.mediaItemId}/pages/${pageNumber}`,
      {
        headers: { Authorization: `Bearer ${token}` },
      },
    );

    if (!response.ok) {
      throw new Error(`Failed to load page ${pageNumber}`);
    }

    const blob = await response.blob();
    const imgUrl = URL.createObjectURL(blob);

    const pageContainer = document.createElement("div");
    pageContainer.className = "vertical-page";
    pageContainer.dataset.pageNumber = pageNumber.toString();

    const img = document.createElement("img");
    img.src = imgUrl;
    img.alt = `Page ${pageNumber}`;
    img.loading = "lazy";

    pageContainer.appendChild(img);
    state.container.appendChild(pageContainer);

    state.loadedPages.add(pageNumber);
    state.loadingPages.delete(pageNumber);

    if (pageNumber < state.totalPages) {
      loadPage(state, pageNumber + 1);
      if (pageNumber + 1 < state.totalPages) {
        loadPage(state, pageNumber + 2);
      }
    }
  } catch (error) {
    console.error(`Failed to load page ${pageNumber}:`, error);
    state.loadingPages.delete(pageNumber);
  }
}

function setupScrollListener(state: VerticalScrollState): void {
  let scrollTimeout: number | undefined;

  state.container.addEventListener("scroll", () => {
    clearTimeout(scrollTimeout);
    scrollTimeout = window.setTimeout(() => {
      checkScrollPosition(state);
    }, 100);
  });
}

function checkScrollPosition(state: VerticalScrollState): void {
  const scrollBottom =
    state.container.scrollHeight -
    state.container.scrollTop -
    state.container.clientHeight;

  if (scrollBottom < state.threshold) {
    const lastPage = Math.max(...state.loadedPages);
    if (lastPage < state.totalPages) {
      loadPage(state, lastPage + 1);
    }
  }

  const currentPage = getCurrentPageFromScroll(state);
  if (currentPage !== state.currentPage) {
    state.currentPage = currentPage;
    window.dispatchEvent(
      new CustomEvent("page-change", {
        detail: { page: currentPage },
      }),
    );
  }
}

function getCurrentPageFromScroll(state: VerticalScrollState): number {
  const pages = Array.from(state.container.querySelectorAll(".vertical-page"));

  for (const page of pages) {
    const rect = page.getBoundingClientRect();
    const containerRect = state.container.getBoundingClientRect();

    const pageMiddle = rect.top + rect.height / 2;
    const viewportMiddle = containerRect.top + containerRect.height / 2;

    if (Math.abs(pageMiddle - viewportMiddle) < containerRect.height / 4) {
      return parseInt((page as HTMLElement).dataset.pageNumber || "1");
    }
  }

  return state.currentPage;
}

function destroyVerticalScroll(state: VerticalScrollState): void {
  const images = Array.from(state.container.querySelectorAll("img"));
  images.forEach((img) => {
    const url = img.src;
    if (url.startsWith("blob:")) {
      URL.revokeObjectURL(url);
    }
  });

  state.container.innerHTML = "";
  state.loadedPages.clear();
  state.loadingPages.clear();
}