/**
 * @module usePageManager
 * @description 리포트 레이아웃의 페이지 단위 CRUD 및 설정 변경을 담당한다.
 * - 페이지 추가/삭제/복제/순서 변경
 * - 현재 활성 페이지 전환 (selectPage)
 * - 개별 페이지 설정(크기, 방향, 여백 등) 업데이트
 * - 전체 페이지 공유 워터마크 설정
 *
 * 페이지 크기 변경 시 기존 컴포넌트 위치/크기를 비율에 따라 자동 재계산한다.
 */

import { useCallback } from "react";
import { v4 as uuidv4 } from "uuid";
import type { ReportLayoutConfig, ReportPage, WatermarkConfig } from "@/types/report";
import type { ToastFunction } from "./internalTypes";
import { generateComponentId } from "@/lib/report/constants";

export interface PageManagerActions {
  addPage: (name?: string) => void;
  deletePage: (pageId: string) => void;
  duplicatePage: (pageId: string) => void;
  reorderPages: (sourceIndex: number, targetIndex: number) => void;
  selectPage: (pageId: string) => void;
  updatePageSettings: (pageId: string, settings: Partial<ReportPage>) => void;
  updateWatermark: (watermark: WatermarkConfig | undefined) => void;
}

interface PageManagerDeps {
  layoutConfig: ReportLayoutConfig;
  setLayoutConfig: React.Dispatch<React.SetStateAction<ReportLayoutConfig>>;
  currentPageId: string | null;
  setCurrentPageId: React.Dispatch<React.SetStateAction<string | null>>;
  /** 페이지 전환 시 선택 상태를 초기화하는 콜백 */
  clearSelection: () => void;
  toast: ToastFunction;
}

/**
 * 페이지 크기가 변경될 때 기존 컴포넌트의 위치/크기를 비율에 맞춰 재계산한다.
 * 소수점 2자리까지만 유지하여 부동소수점 오차를 최소화한다.
 */
function recalculateComponentPositions(
  components: ReportPage["components"],
  oldWidth: number,
  oldHeight: number,
  newWidth: number,
  newHeight: number,
): ReportPage["components"] {
  if (oldWidth === newWidth && oldHeight === newHeight) return components;

  const widthRatio = newWidth / oldWidth;
  const heightRatio = newHeight / oldHeight;

  return components.map((comp) => ({
    ...comp,
    x: Math.round(comp.x * widthRatio * 100) / 100,
    y: Math.round(comp.y * heightRatio * 100) / 100,
    width: Math.round(comp.width * widthRatio * 100) / 100,
    height: Math.round(comp.height * heightRatio * 100) / 100,
  }));
}

export function usePageManager({
  layoutConfig,
  setLayoutConfig,
  currentPageId,
  setCurrentPageId,
  clearSelection,
  toast,
}: PageManagerDeps): PageManagerActions {
  /** 새 페이지를 마지막에 추가하고 해당 페이지로 자동 전환한다. */
  const addPage = useCallback(
    (name?: string) => {
      const newPageId = uuidv4();
      const newPage: ReportPage = {
        page_id: newPageId,
        page_name: name ?? `페이지 ${layoutConfig.pages.length + 1}`,
        page_order: layoutConfig.pages.length,
        width: 210,
        height: 297,
        orientation: "portrait",
        margins: { top: 20, bottom: 20, left: 20, right: 20 },
        background_color: "#ffffff",
        components: [],
      };

      setLayoutConfig((prev) => ({ pages: [...prev.pages, newPage] }));
      setCurrentPageId(newPageId);
      toast({ title: "페이지 추가", description: `${newPage.page_name}이(가) 추가되었습니다.` });
    },
    [layoutConfig.pages.length, setLayoutConfig, setCurrentPageId, toast],
  );

  /**
   * 지정한 페이지를 삭제한다.
   * 마지막 페이지는 삭제 불가. 현재 페이지 삭제 시 나머지 첫 번째 페이지로 이동한다.
   */
  const deletePage = useCallback(
    (pageId: string) => {
      if (layoutConfig.pages.length <= 1) {
        toast({ title: "삭제 불가", description: "최소 1개의 페이지는 필요합니다.", variant: "destructive" });
        return;
      }

      const pageIndex = layoutConfig.pages.findIndex((p) => p.page_id === pageId);
      if (pageIndex === -1) return;

      setLayoutConfig((prev) => ({
        pages: prev.pages
          .filter((p) => p.page_id !== pageId)
          .map((p, idx) => ({ ...p, page_order: idx })),
      }));

      if (currentPageId === pageId) {
        const remaining = layoutConfig.pages.filter((p) => p.page_id !== pageId);
        setCurrentPageId(remaining[0]?.page_id ?? null);
      }

      toast({ title: "페이지 삭제", description: "페이지가 삭제되었습니다." });
    },
    [layoutConfig.pages, currentPageId, setLayoutConfig, setCurrentPageId, toast],
  );

  /** 지정한 페이지를 복제하고 복제된 페이지로 이동한다. 컴포넌트에도 새 ID가 부여된다. */
  const duplicatePage = useCallback(
    (pageId: string) => {
      const sourcePage = layoutConfig.pages.find((p) => p.page_id === pageId);
      if (!sourcePage) return;

      const newPageId = uuidv4();
      const newPage: ReportPage = {
        ...sourcePage,
        page_id: newPageId,
        page_name: `${sourcePage.page_name} (복사)`,
        page_order: layoutConfig.pages.length,
        components: sourcePage.components.map((comp) => ({
          ...comp,
          id: generateComponentId(),
        })),
      };

      setLayoutConfig((prev) => ({ pages: [...prev.pages, newPage] }));
      setCurrentPageId(newPageId);
      toast({ title: "페이지 복제", description: `${newPage.page_name}이(가) 생성되었습니다.` });
    },
    [layoutConfig.pages, setLayoutConfig, setCurrentPageId, toast],
  );

  /** 드래그&드롭으로 페이지 순서를 변경한다. page_order는 인덱스와 동기화된다. */
  const reorderPages = useCallback(
    (sourceIndex: number, targetIndex: number) => {
      if (sourceIndex === targetIndex) return;

      const newPages = [...layoutConfig.pages];
      const [movedPage] = newPages.splice(sourceIndex, 1);
      newPages.splice(targetIndex, 0, movedPage);
      newPages.forEach((page, idx) => { page.page_order = idx; });

      setLayoutConfig({ pages: newPages });
    },
    [layoutConfig.pages, setLayoutConfig],
  );

  /** 지정한 페이지로 전환하고, 기존에 선택된 컴포넌트를 초기화한다. */
  const selectPage = useCallback(
    (pageId: string) => {
      setCurrentPageId(pageId);
      clearSelection();
    },
    [setCurrentPageId, clearSelection],
  );

  /**
   * 페이지의 크기, 방향, 여백, 배경색 등을 업데이트한다.
   * 페이지 크기가 변경될 경우 기존 컴포넌트 위치/크기를 비율에 따라 재계산한다.
   */
  const updatePageSettings = useCallback(
    (pageId: string, settings: Partial<ReportPage>) => {
      setLayoutConfig((prev) => {
        const targetPage = prev.pages.find((p) => p.page_id === pageId);
        if (!targetPage) return prev;

        const isWidthChanging = settings.width !== undefined && settings.width !== targetPage.width;
        const isHeightChanging = settings.height !== undefined && settings.height !== targetPage.height;

        const updatedComponents =
          isWidthChanging || isHeightChanging
            ? recalculateComponentPositions(
                targetPage.components,
                targetPage.width,
                targetPage.height,
                settings.width ?? targetPage.width,
                settings.height ?? targetPage.height,
              )
            : targetPage.components;

        return {
          ...prev,
          pages: prev.pages.map((page) =>
            page.page_id === pageId ? { ...page, ...settings, components: updatedComponents } : page,
          ),
        };
      });
    },
    [setLayoutConfig],
  );

  /**
   * 전체 페이지에 공유되는 워터마크를 설정한다.
   * undefined를 전달하면 워터마크가 제거된다.
   */
  const updateWatermark = useCallback(
    (watermark: WatermarkConfig | undefined) => {
      setLayoutConfig((prev) => ({ ...prev, watermark }));
    },
    [setLayoutConfig],
  );

  return {
    addPage,
    deletePage,
    duplicatePage,
    reorderPages,
    selectPage,
    updatePageSettings,
    updateWatermark,
  };
}
