import type { Panel } from "../comic/panel-detector";
import { detectPanels } from "../comic/panel-detection.service";
import type { ReaderContext } from "../core/reader-context";

let currentPanelIndex = 0;
let currentPagePanels: Panel[] = [];
let context: ReaderContext;

export async function init(readerContext: ReaderContext): Promise<void> {
  context = readerContext;
  setupGestures();
  await loadPanelsIfComic();
}

function setupGestures() {
  const container = context.elements.readerContent;
  if (!container) return;

  const state = {
    touchStartX: 0,
    touchStartY: 0,
    touchStartTime: 0,
    lastTapTime: 0,
    initialPinchDistance: 0,
    scale: 1,
  };

  container.addEventListener(
    "touchstart",
    (e) => {
      if (e.touches.length === 1) {
        state.touchStartX = e.touches[0].clientX;
        state.touchStartY = e.touches[0].clientY;
        state.touchStartTime = Date.now();
      } else if (e.touches.length === 2) {
        state.initialPinchDistance = getPinchDistance(e.touches);
      }
    },
    { passive: true },
  );

  container.addEventListener(
    "touchend",
    (e) => {
      const deltaX = e.changedTouches[0].clientX - state.touchStartX;
      const deltaY = e.changedTouches[0].clientY - state.touchStartY;
      const deltaTime = Date.now() - state.touchStartTime;

      if (Math.abs(deltaX) < 30 && Math.abs(deltaY) < 30 && deltaTime < 300) {
        const now = Date.now();
        if (now - state.lastTapTime < 300) {
          handleDoubleTap();
          state.lastTapTime = 0;
        } else {
          state.lastTapTime = now;
          setTimeout(() => {
            if (state.lastTapTime !== 0) {
              handleTap();
            }
          }, 300);
        }
        return;
      }

      const minSwipeDistance = 50;
      const maxSwipeTime = 500;

      if (deltaTime > maxSwipeTime) return;

      if (Math.abs(deltaX) > Math.abs(deltaY)) {
        if (deltaX > minSwipeDistance) {
          handleSwipeRight();
        } else if (deltaX < -minSwipeDistance) {
          handleSwipeLeft();
        }
      } else {
        if (deltaY > minSwipeDistance) {
          handleSwipeDown();
        } else if (deltaY < -minSwipeDistance) {
          handleSwipeUp();
        }
      }
    },
    { passive: true },
  );

  container.addEventListener(
    "touchmove",
    (e) => {
      if (e.touches.length === 2) {
        const currentDistance = getPinchDistance(e.touches);
        if (state.initialPinchDistance > 0) {
          const scale = currentDistance / state.initialPinchDistance;
          handlePinch(scale);
        }
      }
    },
    { passive: true },
  );
}

function handleSwipeLeft() {
  const metadata = context.getState().readerMetadata;
  if (metadata?.library_type_name === "manga") {
    navigateWithPanels("next");
  } else {
    context.navigation.previousPage();
  }
}

function handleSwipeRight() {
  const metadata = context.getState().readerMetadata;
  if (metadata?.library_type_name === "manga") {
    navigateWithPanels("previous");
  } else {
    context.navigation.nextPage();
  }
}

function handleSwipeUp() {
  const chrome = context.elements.chrome;
  if (chrome) chrome.classList.remove("visible");
}

function handleSwipeDown() {
  const chrome = context.elements.chrome;
  if (chrome) chrome.classList.add("visible");
}

function handleTap() {
  const chrome = context.elements.chrome;
  if (chrome) chrome.classList.toggle("visible");
}

function handleDoubleTap() {
  const container = context.elements.readerContent;
  if (container) {
    const currentTransform = container.style.transform || "";
    const currentScale = currentTransform.match(/scale\(([\d.]+)\)/);
    const scale = currentScale ? parseFloat(currentScale[1]) : 1;
    const newScale = scale === 1 ? 1.5 : 1;
    container.style.transform = `scale(${newScale})`;
    container.style.transformOrigin = "center center";
    context.events.emit("zoomChanged", newScale);
  }
}

function handlePinch(scale: number) {
  const container = context.elements.readerContent;
  if (container && scale >= 0.5 && scale <= 3) {
    container.style.transform = `scale(${scale})`;
    container.style.transformOrigin = "center center";
    context.events.emit("zoomChanged", scale);
  }
}

function getPinchDistance(touches: TouchList): number {
  const dx = touches[0].clientX - touches[1].clientX;
  const dy = touches[0].clientY - touches[1].clientY;
  return Math.sqrt(dx * dx + dy * dy);
}

async function loadPanelsIfComic() {
  const state = context.getState();
  if (
    !state.currentReader ||
    (state.currentReader.type !== "comic" &&
      state.currentReader.type !== "manga")
  ) {
    return;
  }

  const reader = state.currentReader as any;
  if (
    !reader.images ||
    reader.currentPage === undefined ||
    reader.currentPage < 0 ||
    reader.currentPage >= reader.images.length
  ) {
    currentPagePanels = [];
    currentPanelIndex = 0;
    return;
  }

  try {
    const imageBlob = reader.images[reader.currentPage];
    const imageData = await blobToImageData(imageBlob);
    const result = await detectPanels(imageData, false);
    currentPagePanels = result.panels;
    currentPanelIndex = 0;
  } catch (error) {
    console.warn("Failed to load panels:", error);
    currentPagePanels = [];
    currentPanelIndex = 0;
  }
}

async function blobToImageData(blob: Blob): Promise<ImageData> {
  const img = new Image();
  const url = URL.createObjectURL(blob);

  return new Promise((resolve, reject) => {
    img.onload = () => {
      const canvas = document.createElement("canvas");
      canvas.width = img.width;
      canvas.height = img.height;
      const ctx = canvas.getContext("2d");
      if (!ctx) {
        reject(new Error("Failed to get canvas context"));
        return;
      }
      ctx.drawImage(img, 0, 0);
      const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
      URL.revokeObjectURL(url);
      resolve(imageData);
    };
    img.onerror = () => {
      URL.revokeObjectURL(url);
      reject(new Error("Failed to load image"));
    };
    img.src = url;
  });
}

function navigateWithPanels(direction: "next" | "previous") {
  if (currentPagePanels.length === 0) {
    if (direction === "next") {
      context.navigation.nextPage();
    } else {
      context.navigation.previousPage();
    }
    return;
  }

  if (
    direction === "next" &&
    currentPanelIndex < currentPagePanels.length - 1
  ) {
    currentPanelIndex++;
    scrollToPanel(currentPanelIndex);
    return;
  }

  if (direction === "previous" && currentPanelIndex > 0) {
    currentPanelIndex--;
    scrollToPanel(currentPanelIndex);
    return;
  }

  // No more panels, go to next/previous page
  if (direction === "next") {
    context.navigation.nextPage();
  } else {
    context.navigation.previousPage();
  }
}

function scrollToPanel(panelIndex: number) {
  const panel = currentPagePanels[panelIndex];
  if (!panel) return;

  const container = context.elements.readerContent;
  if (!container) return;

  const panelElement =
    container.querySelector(`[data-panel-id="${panel.id}"]`) ||
    container.querySelector(`#${panel.id}`);

  if (panelElement) {
    panelElement.scrollIntoView({ behavior: "smooth", block: "center" });
    document
      .querySelectorAll(".panel-current")
      .forEach((el) => el.classList.remove("panel-current"));
    panelElement.classList.add("panel-current");
  }
}
