/**
 * @module useUIState
 * @description 리포트 디자이너의 UI 전용 상태를 관리한다.
 * - 그리드/스냅/눈금자: 캔버스 보조 도구 표시 여부와 크기
 * - 줌(zoom): 캔버스 확대/축소 배율
 * - 정렬 가이드라인: 드래그 중 다른 컴포넌트와의 정렬선 계산
 * - 패널 접기/펼치기: 좌·우·페이지 리스트 패널 상태
 * - 컴포넌트 설정 모달: 더블클릭 시 열리는 인캔버스 설정 모달 대상 ID
 */

import { useState, useCallback } from "react";
import type { ComponentConfig } from "@/types/report";
import { MM_TO_PX } from "@/lib/report/constants";

/** 캔버스에 표시할 정렬 가이드선 좌표 (px) */
interface AlignmentGuides {
  vertical: number[];
  horizontal: number[];
}

/** 정렬 가이드 계산에 필요한 캔버스 치수 (mm 단위) */
interface CanvasDimensions {
  canvasWidth: number;
  canvasHeight: number;
}

export interface UIStateResult {
  gridSize: number;
  setGridSize: (size: number) => void;
  showGrid: boolean;
  setShowGrid: (show: boolean) => void;
  snapToGrid: boolean;
  setSnapToGrid: (snap: boolean) => void;
  snapValueToGrid: (value: number) => number;
  showRuler: boolean;
  setShowRuler: (show: boolean) => void;
  zoom: number;
  setZoom: (zoom: number) => void;
  fitTrigger: number;
  fitToScreen: () => void;
  alignmentGuides: AlignmentGuides;
  calculateAlignmentGuides: (draggingId: string, x: number, y: number, width: number, height: number) => void;
  clearAlignmentGuides: () => void;
  isPageListCollapsed: boolean;
  setIsPageListCollapsed: (v: boolean) => void;
  isLeftPanelCollapsed: boolean;
  setIsLeftPanelCollapsed: (v: boolean) => void;
  isRightPanelCollapsed: boolean;
  setIsRightPanelCollapsed: (v: boolean) => void;
  componentModalTargetId: string | null;
  openComponentModal: (componentId: string) => void;
  closeComponentModal: () => void;
}

/** 드래그 중 정렬 가이드를 계산할 때 사용하는 오차 허용 범위 (px) */
const ALIGNMENT_THRESHOLD_PX = 5;

export function useUIState(
  /** 정렬 가이드 계산에 필요한 현재 페이지 컴포넌트 목록 */
  components: ComponentConfig[],
  /** 정렬 가이드 계산에 필요한 캔버스 치수 */
  dimensions: CanvasDimensions,
): UIStateResult {
  const { canvasWidth, canvasHeight } = dimensions;

  const [gridSize, setGridSize] = useState(10);
  const [showGrid, setShowGrid] = useState(true);
  const [snapToGrid, setSnapToGrid] = useState(true);
  const [showRuler, setShowRuler] = useState(true);
  const [zoom, setZoom] = useState(1);
  const [fitTrigger, setFitTrigger] = useState(0);
  const [alignmentGuides, setAlignmentGuides] = useState<AlignmentGuides>({ vertical: [], horizontal: [] });
  const [isPageListCollapsed, setIsPageListCollapsed] = useState(false);
  const [isLeftPanelCollapsed, setIsLeftPanelCollapsed] = useState(false);
  const [isRightPanelCollapsed, setIsRightPanelCollapsed] = useState(false);
  const [componentModalTargetId, setComponentModalTargetId] = useState<string | null>(null);

  /** fitToScreen 호출 시 트리거 값을 증가시켜 Canvas가 화면 맞춤을 실행하게 한다. */
  const fitToScreen = useCallback(() => setFitTrigger((n) => n + 1), []);

  /** 인캔버스 설정 모달을 열고 대상 컴포넌트 ID를 등록한다. */
  const openComponentModal = useCallback((componentId: string) => {
    setComponentModalTargetId(componentId);
  }, []);

  /** 인캔버스 설정 모달을 닫는다. */
  const closeComponentModal = useCallback(() => {
    setComponentModalTargetId(null);
  }, []);

  /**
   * 그리드 스냅이 활성화된 경우 value를 gridSize 단위로 반올림한다.
   * 비활성화된 경우 원래 값을 그대로 반환한다.
   */
  const snapValueToGrid = useCallback(
    (value: number): number => {
      if (!snapToGrid) return value;
      return Math.round(value / gridSize) * gridSize;
    },
    [snapToGrid, gridSize],
  );

  /**
   * 드래그 중인 컴포넌트의 위치/크기를 기준으로
   * 다른 컴포넌트 및 캔버스 중앙선과의 정렬 가이드라인을 계산한다.
   *
   * @param draggingId 현재 드래그 중인 컴포넌트 ID (자기 자신 제외용)
   * @param x 드래그 중인 컴포넌트의 현재 x 좌표 (px)
   * @param y 드래그 중인 컴포넌트의 현재 y 좌표 (px)
   * @param width 드래그 중인 컴포넌트의 너비 (px)
   * @param height 드래그 중인 컴포넌트의 높이 (px)
   */
  const calculateAlignmentGuides = useCallback(
    (draggingId: string, x: number, y: number, width: number, height: number) => {
      const verticalLines: number[] = [];
      const horizontalLines: number[] = [];

      const canvasWidthPx = canvasWidth * MM_TO_PX;
      const canvasHeightPx = canvasHeight * MM_TO_PX;
      const canvasCenterX = canvasWidthPx / 2;
      const canvasCenterY = canvasHeightPx / 2;

      const left = x;
      const right = x + width;
      const centerX = x + width / 2;
      const top = y;
      const bottom = y + height;
      const centerY = y + height / 2;

      // 캔버스 중앙선 체크
      if (Math.abs(centerX - canvasCenterX) < ALIGNMENT_THRESHOLD_PX) verticalLines.push(canvasCenterX);
      if (Math.abs(centerY - canvasCenterY) < ALIGNMENT_THRESHOLD_PX) horizontalLines.push(canvasCenterY);

      // 다른 컴포넌트와 비교
      components.forEach((comp) => {
        if (comp.id === draggingId) return;

        const cLeft = comp.x;
        const cRight = comp.x + comp.width;
        const cCenterX = comp.x + comp.width / 2;
        const cTop = comp.y;
        const cBottom = comp.y + comp.height;
        const cCenterY = comp.y + comp.height / 2;

        // 세로 정렬선 (left, right, centerX)
        if (Math.abs(left - cLeft) < ALIGNMENT_THRESHOLD_PX) verticalLines.push(cLeft);
        if (Math.abs(left - cRight) < ALIGNMENT_THRESHOLD_PX) verticalLines.push(cRight);
        if (Math.abs(right - cLeft) < ALIGNMENT_THRESHOLD_PX) verticalLines.push(cLeft);
        if (Math.abs(right - cRight) < ALIGNMENT_THRESHOLD_PX) verticalLines.push(cRight);
        if (Math.abs(centerX - cCenterX) < ALIGNMENT_THRESHOLD_PX) verticalLines.push(cCenterX);

        // 가로 정렬선 (top, bottom, centerY)
        if (Math.abs(top - cTop) < ALIGNMENT_THRESHOLD_PX) horizontalLines.push(cTop);
        if (Math.abs(top - cBottom) < ALIGNMENT_THRESHOLD_PX) horizontalLines.push(cBottom);
        if (Math.abs(bottom - cTop) < ALIGNMENT_THRESHOLD_PX) horizontalLines.push(cTop);
        if (Math.abs(bottom - cBottom) < ALIGNMENT_THRESHOLD_PX) horizontalLines.push(cBottom);
        if (Math.abs(centerY - cCenterY) < ALIGNMENT_THRESHOLD_PX) horizontalLines.push(cCenterY);
      });

      setAlignmentGuides({
        vertical: Array.from(new Set(verticalLines)),
        horizontal: Array.from(new Set(horizontalLines)),
      });
    },
    [components, canvasWidth, canvasHeight],
  );

  /** 드래그 종료 후 정렬 가이드라인을 초기화한다. */
  const clearAlignmentGuides = useCallback(() => {
    setAlignmentGuides({ vertical: [], horizontal: [] });
  }, []);

  return {
    gridSize,
    setGridSize,
    showGrid,
    setShowGrid,
    snapToGrid,
    setSnapToGrid,
    snapValueToGrid,
    showRuler,
    setShowRuler,
    zoom,
    setZoom,
    fitTrigger,
    fitToScreen,
    alignmentGuides,
    calculateAlignmentGuides,
    clearAlignmentGuides,
    isPageListCollapsed,
    setIsPageListCollapsed,
    isLeftPanelCollapsed,
    setIsLeftPanelCollapsed,
    isRightPanelCollapsed,
    setIsRightPanelCollapsed,
    componentModalTargetId,
    openComponentModal,
    closeComponentModal,
  };
}
