/**
 * @module useAlignmentActions
 * @description 선택된 컴포넌트들의 위치/크기를 일괄 조정하는 정렬 기능을 제공한다.
 * - 엣지 정렬: 좌/우/상/하 기준으로 정렬
 * - 중앙 정렬: 가로/세로 중앙으로 정렬
 * - 균등 배치: 컴포넌트 간 간격을 동일하게 분배 (최소 3개 필요)
 * - 크기 동일화: 첫 번째 선택 컴포넌트 기준으로 너비/높이/둘 다 통일
 *
 * 모든 함수는 2개 이상(균등 배치는 3개 이상) 선택된 경우에만 동작한다.
 */

import { useCallback } from "react";
import type { ComponentConfig } from "@/types/report";
import type { SetComponentsFn, ToastFunction } from "./internalTypes";

export interface AlignmentActions {
  alignLeft: () => void;
  alignRight: () => void;
  alignTop: () => void;
  alignBottom: () => void;
  alignCenterHorizontal: () => void;
  alignCenterVertical: () => void;
  distributeHorizontal: () => void;
  distributeVertical: () => void;
  makeSameWidth: () => void;
  makeSameHeight: () => void;
  makeSameSize: () => void;
}

interface AlignmentDeps {
  components: ComponentConfig[];
  selectedComponentIds: string[];
  setComponents: SetComponentsFn;
  toast: ToastFunction;
}

/** 선택된 컴포넌트를 업데이트 맵에서 찾아 교체하는 공통 헬퍼 */
function applyUpdates(
  prev: ComponentConfig[],
  updates: ComponentConfig[],
): ComponentConfig[] {
  const updateMap = new Map(updates.map((u) => [u.id, u]));
  return prev.map((c) => updateMap.get(c.id) ?? c);
}

export function useAlignmentActions({
  components,
  selectedComponentIds,
  setComponents,
  toast,
}: AlignmentDeps): AlignmentActions {
  /** 선택된 컴포넌트 배열 반환 (정렬 함수 내부 공통 사용) */
  const getSelected = useCallback(
    () => components.filter((c) => selectedComponentIds.includes(c.id)),
    [components, selectedComponentIds],
  );

  /** 모든 선택 컴포넌트의 x를 가장 왼쪽 x 기준으로 정렬 */
  const alignLeft = useCallback(() => {
    const selected = getSelected();
    if (selected.length < 2) return;
    const minX = Math.min(...selected.map((c) => c.x));
    setComponents((prev) => applyUpdates(prev, selected.map((c) => ({ ...c, x: minX }))));
    toast({ title: "정렬 완료", description: "왼쪽 정렬되었습니다." });
  }, [getSelected, setComponents, toast]);

  /** 모든 선택 컴포넌트의 오른쪽 엣지를 가장 오른쪽 엣지 기준으로 정렬 */
  const alignRight = useCallback(() => {
    const selected = getSelected();
    if (selected.length < 2) return;
    const maxRight = Math.max(...selected.map((c) => c.x + c.width));
    setComponents((prev) => applyUpdates(prev, selected.map((c) => ({ ...c, x: maxRight - c.width }))));
    toast({ title: "정렬 완료", description: "오른쪽 정렬되었습니다." });
  }, [getSelected, setComponents, toast]);

  /** 모든 선택 컴포넌트의 y를 가장 위쪽 y 기준으로 정렬 */
  const alignTop = useCallback(() => {
    const selected = getSelected();
    if (selected.length < 2) return;
    const minY = Math.min(...selected.map((c) => c.y));
    setComponents((prev) => applyUpdates(prev, selected.map((c) => ({ ...c, y: minY }))));
    toast({ title: "정렬 완료", description: "위쪽 정렬되었습니다." });
  }, [getSelected, setComponents, toast]);

  /** 모든 선택 컴포넌트의 아래쪽 엣지를 가장 아래쪽 엣지 기준으로 정렬 */
  const alignBottom = useCallback(() => {
    const selected = getSelected();
    if (selected.length < 2) return;
    const maxBottom = Math.max(...selected.map((c) => c.y + c.height));
    setComponents((prev) => applyUpdates(prev, selected.map((c) => ({ ...c, y: maxBottom - c.height }))));
    toast({ title: "정렬 완료", description: "아래쪽 정렬되었습니다." });
  }, [getSelected, setComponents, toast]);

  /** 선택 컴포넌트들의 수평 중앙을 전체 범위의 중앙으로 정렬 */
  const alignCenterHorizontal = useCallback(() => {
    const selected = getSelected();
    if (selected.length < 2) return;
    const minX = Math.min(...selected.map((c) => c.x));
    const maxRight = Math.max(...selected.map((c) => c.x + c.width));
    const centerX = (minX + maxRight) / 2;
    setComponents((prev) => applyUpdates(prev, selected.map((c) => ({ ...c, x: centerX - c.width / 2 }))));
    toast({ title: "정렬 완료", description: "가로 중앙 정렬되었습니다." });
  }, [getSelected, setComponents, toast]);

  /** 선택 컴포넌트들의 수직 중앙을 전체 범위의 중앙으로 정렬 */
  const alignCenterVertical = useCallback(() => {
    const selected = getSelected();
    if (selected.length < 2) return;
    const minY = Math.min(...selected.map((c) => c.y));
    const maxBottom = Math.max(...selected.map((c) => c.y + c.height));
    const centerY = (minY + maxBottom) / 2;
    setComponents((prev) => applyUpdates(prev, selected.map((c) => ({ ...c, y: centerY - c.height / 2 }))));
    toast({ title: "정렬 완료", description: "세로 중앙 정렬되었습니다." });
  }, [getSelected, setComponents, toast]);

  /** 3개 이상 선택된 컴포넌트를 가로 방향으로 균등하게 배치 */
  const distributeHorizontal = useCallback(() => {
    const selected = getSelected();
    if (selected.length < 3) return;
    const sorted = [...selected].sort((a, b) => a.x - b.x);
    const totalWidth = sorted.reduce((sum, c) => sum + c.width, 0);
    const span = sorted[sorted.length - 1].x + sorted[sorted.length - 1].width - sorted[0].x;
    const gap = (span - totalWidth) / (sorted.length - 1);
    let currentX = sorted[0].x;
    const updates = sorted.map((c) => {
      const updated = { ...c, x: currentX };
      currentX += c.width + gap;
      return updated;
    });
    setComponents((prev) => applyUpdates(prev, updates));
    toast({ title: "정렬 완료", description: "가로 균등 배치되었습니다." });
  }, [getSelected, setComponents, toast]);

  /** 3개 이상 선택된 컴포넌트를 세로 방향으로 균등하게 배치 */
  const distributeVertical = useCallback(() => {
    const selected = getSelected();
    if (selected.length < 3) return;
    const sorted = [...selected].sort((a, b) => a.y - b.y);
    const totalHeight = sorted.reduce((sum, c) => sum + c.height, 0);
    const span = sorted[sorted.length - 1].y + sorted[sorted.length - 1].height - sorted[0].y;
    const gap = (span - totalHeight) / (sorted.length - 1);
    let currentY = sorted[0].y;
    const updates = sorted.map((c) => {
      const updated = { ...c, y: currentY };
      currentY += c.height + gap;
      return updated;
    });
    setComponents((prev) => applyUpdates(prev, updates));
    toast({ title: "정렬 완료", description: "세로 균등 배치되었습니다." });
  }, [getSelected, setComponents, toast]);

  /** 선택된 모든 컴포넌트의 너비를 첫 번째 컴포넌트 너비로 통일 */
  const makeSameWidth = useCallback(() => {
    const selected = getSelected();
    if (selected.length < 2) return;
    const targetWidth = selected[0].width;
    setComponents((prev) => applyUpdates(prev, selected.map((c) => ({ ...c, width: targetWidth }))));
    toast({ title: "크기 조정 완료", description: "같은 너비로 조정되었습니다." });
  }, [getSelected, setComponents, toast]);

  /** 선택된 모든 컴포넌트의 높이를 첫 번째 컴포넌트 높이로 통일 */
  const makeSameHeight = useCallback(() => {
    const selected = getSelected();
    if (selected.length < 2) return;
    const targetHeight = selected[0].height;
    setComponents((prev) => applyUpdates(prev, selected.map((c) => ({ ...c, height: targetHeight }))));
    toast({ title: "크기 조정 완료", description: "같은 높이로 조정되었습니다." });
  }, [getSelected, setComponents, toast]);

  /** 선택된 모든 컴포넌트의 너비/높이를 첫 번째 컴포넌트 크기로 통일 */
  const makeSameSize = useCallback(() => {
    const selected = getSelected();
    if (selected.length < 2) return;
    const { width: targetWidth, height: targetHeight } = selected[0];
    setComponents((prev) => applyUpdates(prev, selected.map((c) => ({ ...c, width: targetWidth, height: targetHeight }))));
    toast({ title: "크기 조정 완료", description: "같은 크기로 조정되었습니다." });
  }, [getSelected, setComponents, toast]);

  return {
    alignLeft,
    alignRight,
    alignTop,
    alignBottom,
    alignCenterHorizontal,
    alignCenterVertical,
    distributeHorizontal,
    distributeVertical,
    makeSameWidth,
    makeSameHeight,
    makeSameSize,
  };
}
