/**
 * @module useLayerActions
 * @description 캔버스에서 컴포넌트의 레이어 순서, 잠금, 그룹화를 관리한다.
 *
 * - 레이어 순서: bringToFront / sendToBack / bringForward / sendBackward
 *   zIndex를 직접 조작하며, 앞/뒤 한 단계 이동 시 전체 컴포넌트를 재정렬하여
 *   zIndex가 1부터 연속되도록 유지한다.
 *
 * - 잠금 관리: toggleLock / lockComponents / unlockComponents
 *   잠긴 컴포넌트는 이동/편집/복사에서 제외된다.
 *
 * - 그룹화: groupComponents / ungroupComponents
 *   groupId 필드로 그룹을 식별하며, 그룹 해제 시 해당 groupId를 가진
 *   모든 컴포넌트에서 groupId를 제거한다.
 */

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

export interface LayerActions {
  bringToFront: () => void;
  sendToBack: () => void;
  bringForward: () => void;
  sendBackward: () => void;
  toggleLock: () => void;
  lockComponents: () => void;
  unlockComponents: () => void;
  groupComponents: () => void;
  ungroupComponents: () => void;
}

interface LayerDeps {
  components: ComponentConfig[];
  selectedComponentId: string | null;
  selectedComponentIds: string[];
  setComponents: SetComponentsFn;
  toast: ToastFunction;
}

export function useLayerActions({
  components,
  selectedComponentId,
  selectedComponentIds,
  setComponents,
  toast,
}: LayerDeps): LayerActions {
  /**
   * 단일/다중 선택 모두를 지원하는 대상 ID 배열 반환.
   * selectedComponentIds가 비어 있으면 selectedComponentId를 사용한다.
   */
  const getTargetIds = useCallback((): string[] => {
    if (selectedComponentIds.length > 0) return selectedComponentIds;
    return selectedComponentId ? [selectedComponentId] : [];
  }, [selectedComponentId, selectedComponentIds]);

  /** 선택된 컴포넌트를 모든 컴포넌트 중 가장 앞으로 이동 */
  const bringToFront = useCallback(() => {
    const ids = getTargetIds();
    if (ids.length === 0) return;
    const maxZIndex = Math.max(...components.map((c) => c.zIndex));
    setComponents((prev) =>
      prev.map((c) => (ids.includes(c.id) ? { ...c, zIndex: maxZIndex + 1 } : c)),
    );
    toast({ title: "레이어 변경", description: "맨 앞으로 이동했습니다." });
  }, [getTargetIds, components, setComponents, toast]);

  /** 선택된 컴포넌트를 모든 컴포넌트 중 가장 뒤로 이동 (최소 zIndex = 1) */
  const sendToBack = useCallback(() => {
    const ids = getTargetIds();
    if (ids.length === 0) return;
    const minZIndex = Math.min(...components.map((c) => c.zIndex));
    setComponents((prev) =>
      prev.map((c) => (ids.includes(c.id) ? { ...c, zIndex: Math.max(1, minZIndex - 1) } : c)),
    );
    toast({ title: "레이어 변경", description: "맨 뒤로 이동했습니다." });
  }, [getTargetIds, components, setComponents, toast]);

  /** 선택된 컴포넌트를 한 단계 앞으로 이동. 전체 zIndex를 재정렬하여 연속성 유지. */
  const bringForward = useCallback(() => {
    const ids = getTargetIds();
    if (ids.length === 0) return;
    setComponents((prev) => {
      const sorted = [...prev].sort((a, b) => a.zIndex - b.zIndex);
      const reindexed = sorted.map((c, i) => ({ ...c, zIndex: i }));
      return reindexed.map((c) =>
        ids.includes(c.id) ? { ...c, zIndex: Math.min(c.zIndex + 1, reindexed.length - 1) } : c,
      );
    });
    toast({ title: "레이어 변경", description: "한 단계 앞으로 이동했습니다." });
  }, [getTargetIds, setComponents, toast]);

  /** 선택된 컴포넌트를 한 단계 뒤로 이동. 전체 zIndex를 재정렬하여 연속성 유지. */
  const sendBackward = useCallback(() => {
    const ids = getTargetIds();
    if (ids.length === 0) return;
    setComponents((prev) => {
      const sorted = [...prev].sort((a, b) => a.zIndex - b.zIndex);
      const reindexed = sorted.map((c, i) => ({ ...c, zIndex: i + 1 }));
      return reindexed.map((c) =>
        ids.includes(c.id) ? { ...c, zIndex: Math.max(c.zIndex - 1, 1) } : c,
      );
    });
    toast({ title: "레이어 변경", description: "한 단계 뒤로 이동했습니다." });
  }, [getTargetIds, setComponents, toast]);

  /** 선택된 컴포넌트의 잠금 상태를 토글한다. */
  const toggleLock = useCallback(() => {
    const ids = getTargetIds();
    if (ids.length === 0) return;
    const isCurrentlyLocked = components.find((c) => ids.includes(c.id))?.locked === true;
    setComponents((prev) =>
      prev.map((c) => (ids.includes(c.id) ? { ...c, locked: !c.locked } : c)),
    );
    toast({
      title: isCurrentlyLocked ? "잠금 해제" : "잠금 설정",
      description: isCurrentlyLocked
        ? "선택된 컴포넌트의 잠금이 해제되었습니다."
        : "선택된 컴포넌트가 잠겼습니다.",
    });
  }, [getTargetIds, components, setComponents, toast]);

  /** 선택된 컴포넌트를 잠근다. */
  const lockComponents = useCallback(() => {
    const ids = getTargetIds();
    if (ids.length === 0) return;
    setComponents((prev) => prev.map((c) => (ids.includes(c.id) ? { ...c, locked: true } : c)));
    toast({ title: "잠금 설정", description: "선택된 컴포넌트가 잠겼습니다." });
  }, [getTargetIds, setComponents, toast]);

  /** 선택된 컴포넌트의 잠금을 해제한다. */
  const unlockComponents = useCallback(() => {
    const ids = getTargetIds();
    if (ids.length === 0) return;
    setComponents((prev) => prev.map((c) => (ids.includes(c.id) ? { ...c, locked: false } : c)));
    toast({ title: "잠금 해제", description: "선택된 컴포넌트의 잠금이 해제되었습니다." });
  }, [getTargetIds, setComponents, toast]);

  /** 2개 이상 선택된 컴포넌트에 동일한 groupId를 부여하여 그룹으로 묶는다. */
  const groupComponents = useCallback(() => {
    if (selectedComponentIds.length < 2) {
      toast({ title: "그룹화 불가", description: "2개 이상의 컴포넌트를 선택해야 합니다.", variant: "destructive" });
      return;
    }
    const newGroupId = `group_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
    setComponents((prev) =>
      prev.map((c) => (selectedComponentIds.includes(c.id) ? { ...c, groupId: newGroupId } : c)),
    );
    toast({ title: "그룹화 완료", description: `${selectedComponentIds.length}개의 컴포넌트가 그룹화되었습니다.` });
  }, [selectedComponentIds, setComponents, toast]);

  /**
   * 선택된 컴포넌트가 속한 그룹 전체를 해제한다.
   * 같은 groupId를 가진 컴포넌트 모두에서 groupId가 제거된다.
   */
  const ungroupComponents = useCallback(() => {
    const ids = getTargetIds();
    if (ids.length === 0) {
      toast({ title: "그룹 해제 불가", description: "그룹을 해제할 컴포넌트를 선택해주세요.", variant: "destructive" });
      return;
    }

    const groupIds = new Set<string>();
    components.forEach((c) => {
      if (ids.includes(c.id) && c.groupId) groupIds.add(c.groupId);
    });

    if (groupIds.size === 0) {
      toast({ title: "그룹 해제 불가", description: "선택된 컴포넌트 중 그룹화된 것이 없습니다.", variant: "destructive" });
      return;
    }

    setComponents((prev) =>
      prev.map((c) => {
        if (c.groupId && groupIds.has(c.groupId)) {
          // eslint-disable-next-line @typescript-eslint/no-unused-vars
          const { groupId, ...rest } = c;
          return rest as ComponentConfig;
        }
        return c;
      }),
    );

    toast({ title: "그룹 해제 완료", description: `${groupIds.size}개의 그룹이 해제되었습니다.` });
  }, [getTargetIds, components, setComponents, toast]);

  return {
    bringToFront,
    sendToBack,
    bringForward,
    sendBackward,
    toggleLock,
    lockComponents,
    unlockComponents,
    groupComponents,
    ungroupComponents,
  };
}
