"use client";

import React, { useState, useRef, useEffect, useMemo } from "react";
import { ComponentRendererProps } from "@/types/component";
import { ButtonPrimaryConfig } from "./types";
import {
  ButtonActionExecutor,
  ButtonActionContext,
  ButtonActionType,
  DEFAULT_BUTTON_ACTIONS,
} from "@/lib/utils/buttonActions";
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { toast } from "sonner";
import { filterDOMProps } from "@/lib/utils/domPropsFilter";
import { useCurrentFlowStep } from "@/stores/flowStepStore";
import { useScreenPreview } from "@/contexts/ScreenPreviewContext";
import { useScreenContextOptional } from "@/contexts/ScreenContext";
import { useSplitPanelContext, SplitPanelPosition } from "@/contexts/SplitPanelContext";
import { applyMappingRules } from "@/lib/utils/dataMapping";
import { apiClient } from "@/lib/api/client";
import { V2ErrorBoundary, v2EventBus, V2_EVENTS } from "@/lib/v2-core";
import { checkAllRequiredFieldsFilled } from "@/lib/utils/formValidation";

export interface ButtonPrimaryComponentProps extends ComponentRendererProps {
  config?: ButtonPrimaryConfig;
  // 추가 props
  screenId?: number;
  tableName?: string;
  userId?: string; // 🆕 현재 사용자 ID
  userName?: string; // 🆕 현재 사용자 이름
  companyCode?: string; // 🆕 현재 사용자의 회사 코드
  onRefresh?: () => void;
  onClose?: () => void;
  onFlowRefresh?: () => void;
  onSave?: () => Promise<void>; // 🆕 EditModal의 handleSave 콜백

  // 폼 데이터 관련
  originalData?: Record<string, any>; // 부분 업데이트용 원본 데이터

  // 테이블 선택된 행 정보 (다중 선택 액션용)
  selectedRows?: any[];
  selectedRowsData?: any[];

  // 테이블 정렬 정보 (엑셀 다운로드용)
  sortBy?: string;
  sortOrder?: "asc" | "desc";
  columnOrder?: string[];
  tableDisplayData?: any[]; // 화면에 표시된 데이터 (컬럼 순서 포함)

  // 플로우 선택된 데이터 정보 (플로우 위젯 선택 액션용)
  flowSelectedData?: any[];
  flowSelectedStepId?: number | null;

  // 🆕 같은 화면의 모든 컴포넌트 (TableList 자동 감지용)
  allComponents?: any[];

  // 🆕 부모창에서 전달된 그룹 데이터 (모달에서 부모 데이터 접근용)
  groupedData?: Record<string, any>[];
}

/**
 * ButtonPrimary 컴포넌트
 * button-primary 컴포넌트입니다
 */
export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
  component,
  isDesignMode = false,
  isSelected = false,
  isInteractive = false,
  onClick,
  onDragStart,
  onDragEnd,
  config,
  className,
  style,
  formData,
  originalData,
  onFormDataChange,
  screenId,
  tableName,
  userId, // 🆕 사용자 ID
  userName, // 🆕 사용자 이름
  companyCode, // 🆕 회사 코드
  onRefresh,
  onClose,
  onFlowRefresh,
  onSave, // 🆕 EditModal의 handleSave 콜백
  sortBy, // 🆕 정렬 컬럼
  sortOrder, // 🆕 정렬 방향
  columnOrder, // 🆕 컬럼 순서
  tableDisplayData, // 🆕 화면에 표시된 데이터
  selectedRows,
  selectedRowsData,
  flowSelectedData,
  flowSelectedStepId,
  allComponents, // 🆕 같은 화면의 모든 컴포넌트
  groupedData, // 🆕 부모창에서 전달된 그룹 데이터
  ...props
}) => {
  const { isPreviewMode } = useScreenPreview(); // 프리뷰 모드 확인
  const screenContext = useScreenContextOptional(); // 화면 컨텍스트
  const splitPanelContext = useSplitPanelContext(); // 분할 패널 컨텍스트
  // 🆕 ScreenContext에서 splitPanelPosition 가져오기 (중첩 화면에서도 작동)
  const splitPanelPosition = screenContext?.splitPanelPosition;

  // 🆕 tableName이 props로 전달되지 않으면 ScreenContext에서 가져오기
  const effectiveTableName = tableName || screenContext?.tableName;
  const effectiveScreenId = screenId || screenContext?.screenId;

  // 🆕 props에서 onSave 추출 (명시적으로 선언되지 않은 경우 ...props에서 추출)
  const propsOnSave = (props as any).onSave as (() => Promise<void>) | undefined;
  const finalOnSave = onSave || propsOnSave;

  // 🆕 플로우 단계별 표시 제어
  const flowConfig = (component as any).webTypeConfig?.flowVisibilityConfig;
  const currentStep = useCurrentFlowStep(flowConfig?.targetFlowComponentId);

  // 🆕 버튼 표시 여부 계산
  const shouldShowButton = useMemo(() => {
    // 플로우 제어 비활성화 시 항상 표시
    if (!flowConfig?.enabled) {
      return true;
    }

    // 플로우 단계가 선택되지 않은 경우 처리
    if (currentStep === null) {
      // 🔧 화이트리스트 모드일 때는 단계 미선택 시 숨김
      if (flowConfig.mode === "whitelist") {
        return false;
      }
      // 블랙리스트나 all 모드는 표시
      return true;
    }

    const { mode, visibleSteps = [], hiddenSteps = [] } = flowConfig;

    let result = true;
    if (mode === "whitelist") {
      result = visibleSteps.includes(currentStep);
    } else if (mode === "blacklist") {
      result = !hiddenSteps.includes(currentStep);
    } else if (mode === "all") {
      result = true;
    }

    return result;
  }, [flowConfig, currentStep, component.id, component.label]);

  // 🆕 운행알림 버튼 조건부 비활성화 (출발지/도착지 필수, 상태 체크)
  // 상태는 API로 조회 (formData에 없는 경우)
  const [vehicleStatus, setVehicleStatus] = useState<string | null>(null);
  const [statusLoading, setStatusLoading] = useState(false);

  // 상태 조회 (operation_control + enableOnStatusCheck일 때)
  const actionConfig = component.componentConfig?.action;
  const shouldFetchStatus = actionConfig?.type === "operation_control" && actionConfig?.enableOnStatusCheck && userId;
  const statusTableName = actionConfig?.statusCheckTableName || "vehicles";
  const statusKeyField = actionConfig?.statusCheckKeyField || "user_id";
  const statusFieldName = actionConfig?.statusCheckField || "status";

  useEffect(() => {
    if (!shouldFetchStatus) return;

    let isMounted = true;

    const fetchStatus = async () => {
      if (!isMounted) return;

      try {
        const response = await apiClient.post(`/table-management/tables/${statusTableName}/data`, {
          page: 1,
          size: 1,
          search: { [statusKeyField]: userId },
          autoFilter: true,
        });

        if (!isMounted) return;

        const rows = response.data?.data?.data || response.data?.data?.rows || response.data?.rows || [];
        const firstRow = Array.isArray(rows) ? rows[0] : null;

        if (response.data?.success && firstRow) {
          const newStatus = firstRow[statusFieldName];
          if (newStatus !== vehicleStatus) {
            // console.log("🔄 [ButtonPrimary] 상태 변경 감지:", { 이전: vehicleStatus, 현재: newStatus, buttonLabel: component.label });
          }
          setVehicleStatus(newStatus);
        } else {
          setVehicleStatus(null);
        }
      } catch (error: any) {
        // console.error("❌ [ButtonPrimary] 상태 조회 오류:", error?.message);
        if (isMounted) setVehicleStatus(null);
      } finally {
        if (isMounted) setStatusLoading(false);
      }
    };

    // 즉시 실행
    setStatusLoading(true);
    fetchStatus();

    // 2초마다 갱신
    const interval = setInterval(fetchStatus, 2000);

    return () => {
      isMounted = false;
      clearInterval(interval);
    };
  }, [shouldFetchStatus, statusTableName, statusKeyField, statusFieldName, userId, component.label]);

  // 버튼 비활성화 조건 계산
  const isOperationButtonDisabled = useMemo(() => {
    const actionConfig = component.componentConfig?.action;

    if (actionConfig?.type !== "operation_control") return false;

    // 1. 출발지/도착지 필수 체크
    if (actionConfig?.requireLocationFields) {
      const departureField = actionConfig.trackingDepartureField || "departure";
      const destinationField = actionConfig.trackingArrivalField || "destination";

      const departure = formData?.[departureField];
      const destination = formData?.[destinationField];

      // console.log("🔍 [ButtonPrimary] 출발지/도착지 체크:", {
      //   departureField, destinationField, departure, destination,
      //   buttonLabel: component.label
      // });

      if (!departure || departure === "" || !destination || destination === "") {
        // console.log("🚫 [ButtonPrimary] 출발지/도착지 미선택 → 비활성화:", component.label);
        return true;
      }
    }

    // 2. 상태 기반 활성화 조건 (API로 조회한 vehicleStatus 우선 사용)
    if (actionConfig?.enableOnStatusCheck) {
      const statusField = actionConfig.statusCheckField || "status";
      // API 조회 결과를 우선 사용 (실시간 DB 상태 반영)
      const currentStatus = vehicleStatus || formData?.[statusField];

      const conditionType = actionConfig.statusConditionType || "enableOn";
      const conditionValues = (actionConfig.statusConditionValues || "")
        .split(",")
        .map((v: string) => v.trim())
        .filter((v: string) => v);

      // console.log("🔍 [ButtonPrimary] 상태 조건 체크:", {
      //   statusField,
      //   formDataStatus: formData?.[statusField],
      //   apiStatus: vehicleStatus,
      //   currentStatus,
      //   conditionType,
      //   conditionValues,
      //   buttonLabel: component.label,
      // });

      // 상태 로딩 중이면 비활성화
      if (statusLoading) {
        // console.log("⏳ [ButtonPrimary] 상태 로딩 중 → 비활성화:", component.label);
        return true;
      }

      // 상태값이 없으면 → 비활성화 (조건 확인 불가)
      if (!currentStatus) {
        // console.log("🚫 [ButtonPrimary] 상태값 없음 → 비활성화:", component.label);
        return true;
      }

      if (conditionValues.length > 0) {
        if (conditionType === "enableOn") {
          // 이 상태일 때만 활성화
          if (!conditionValues.includes(currentStatus)) {
            // console.log(`🚫 [ButtonPrimary] 상태 ${currentStatus} ∉ [${conditionValues}] → 비활성화:`, component.label);
            return true;
          }
        } else if (conditionType === "disableOn") {
          // 이 상태일 때 비활성화
          if (conditionValues.includes(currentStatus)) {
            // console.log(`🚫 [ButtonPrimary] 상태 ${currentStatus} ∈ [${conditionValues}] → 비활성화:`, component.label);
            return true;
          }
        }
      }
    }

    // console.log("✅ [ButtonPrimary] 버튼 활성화:", component.label);
    return false;
  }, [component.componentConfig?.action, formData, vehicleStatus, statusLoading, component.label]);

  // 🆕 modalDataStore에서 선택된 데이터 확인 (분할 패널 등에서 저장됨)
  const [modalStoreData, setModalStoreData] = useState<Record<string, any[]>>({});

  // modalDataStore 상태 구독 (실시간 업데이트)
  useEffect(() => {
    const actionConfig = component.componentConfig?.action;
    if (!actionConfig?.requireRowSelection) return;

    // 동적 import로 modalDataStore 구독
    let unsubscribe: (() => void) | undefined;

    import("@/stores/modalDataStore").then(({ useModalDataStore }) => {
      // 초기값 설정
      setModalStoreData(useModalDataStore.getState().dataRegistry);

      // 상태 변경 구독
      unsubscribe = useModalDataStore.subscribe((state) => {
        setModalStoreData(state.dataRegistry);
      });
    });

    return () => {
      unsubscribe?.();
    };
  }, [component.componentConfig?.action?.requireRowSelection]);

  // 🆕 행 선택 기반 비활성화 조건 계산
  const isRowSelectionDisabled = useMemo(() => {
    const actionConfig = component.componentConfig?.action;

    // requireRowSelection이 활성화되어 있지 않으면 비활성화하지 않음
    if (!actionConfig?.requireRowSelection) {
      return false;
    }

    const rowSelectionSource = actionConfig.rowSelectionSource || "auto";
    const allowMultiRowSelection = actionConfig.allowMultiRowSelection ?? true;

    // 선택된 데이터 확인
    let hasSelection = false;
    let selectionCount = 0;
    let selectionSource = "";

    // 1. 자동 감지 모드 또는 테이블 리스트 모드
    if (rowSelectionSource === "auto" || rowSelectionSource === "tableList") {
      // TableList에서 선택된 행 확인 (props로 전달됨)
      if (selectedRowsData && selectedRowsData.length > 0) {
        hasSelection = true;
        selectionCount = selectedRowsData.length;
        selectionSource = "tableList (selectedRowsData)";
      }
      // 또는 selectedRows prop 확인
      else if (selectedRows && selectedRows.length > 0) {
        hasSelection = true;
        selectionCount = selectedRows.length;
        selectionSource = "tableList (selectedRows)";
      }
    }

    // 2. 분할 패널 좌측 선택 데이터 확인
    if (rowSelectionSource === "auto" || rowSelectionSource === "splitPanelLeft") {
      // SplitPanelContext에서 확인
      if (splitPanelContext?.selectedLeftData && Object.keys(splitPanelContext.selectedLeftData).length > 0) {
        if (!hasSelection) {
          hasSelection = true;
          selectionCount = 1;
          selectionSource = "splitPanelLeft (context)";
        }
      }

      // 🆕 modalDataStore에서도 확인 (SplitPanelLayoutComponent에서 저장)
      if (!hasSelection && Object.keys(modalStoreData).length > 0) {
        // modalDataStore에서 데이터가 있는지 확인
        for (const [sourceId, items] of Object.entries(modalStoreData)) {
          if (items && items.length > 0) {
            hasSelection = true;
            selectionCount = items.length;
            selectionSource = `modalDataStore (${sourceId})`;
            break;
          }
        }
      }
    }

    // 3. 플로우 위젯 선택 데이터 확인
    if (rowSelectionSource === "auto" || rowSelectionSource === "flowWidget") {
      // 플로우 위젯 선택 데이터 확인
      if (!hasSelection && flowSelectedData && flowSelectedData.length > 0) {
        hasSelection = true;
        selectionCount = flowSelectedData.length;
        selectionSource = "flowWidget";
      }
    }

    // 디버깅 로그
    console.log("🔍 [ButtonPrimary] 행 선택 체크:", component.label, {
      rowSelectionSource,
      hasSelection,
      selectionCount,
      selectionSource,
      hasSplitPanelContext: !!splitPanelContext,
      selectedLeftData: splitPanelContext?.selectedLeftData,
      selectedRowsData: selectedRowsData?.length,
      selectedRows: selectedRows?.length,
      flowSelectedData: flowSelectedData?.length,
      modalStoreDataKeys: Object.keys(modalStoreData),
    });

    // 선택된 데이터가 없으면 비활성화
    if (!hasSelection) {
      return true;
    }

    // 다중 선택 허용하지 않는 경우, 정확히 1개만 선택되어야 함
    if (!allowMultiRowSelection && selectionCount !== 1) {
      return true;
    }

    return false;
  }, [
    component.componentConfig?.action,
    component.label,
    selectedRows,
    selectedRowsData,
    splitPanelContext?.selectedLeftData,
    flowSelectedData,
    splitPanelContext,
    modalStoreData,
  ]);

  // 확인 다이얼로그 상태
  const [showConfirmDialog, setShowConfirmDialog] = useState(false);
  const [pendingAction, setPendingAction] = useState<{
    type: ButtonActionType;
    config: any;
    context: ButtonActionContext;
  } | null>(null);

  // 토스트 정리를 위한 ref
  const currentLoadingToastRef = useRef<string | number | undefined>(undefined);

  // 컴포넌트 언마운트 시 토스트 정리
  useEffect(() => {
    return () => {
      if (currentLoadingToastRef.current !== undefined) {
        toast.dismiss(currentLoadingToastRef.current);
        currentLoadingToastRef.current = undefined;
      }
    };
  }, []);

  // 삭제 액션 감지 로직 (실제 필드명 사용)
  const isDeleteAction = () => {
    const deleteKeywords = ["삭제", "delete", "remove", "제거", "del"];
    return (
      component.componentConfig?.action?.type === "delete" ||
      component.config?.action?.type === "delete" ||
      component.webTypeConfig?.actionType === "delete" ||
      component.text?.toLowerCase().includes("삭제") ||
      component.text?.toLowerCase().includes("delete") ||
      component.label?.toLowerCase().includes("삭제") ||
      component.label?.toLowerCase().includes("delete") ||
      deleteKeywords.some(
        (keyword) =>
          component.config?.buttonText?.toLowerCase().includes(keyword) ||
          component.config?.text?.toLowerCase().includes(keyword),
      )
    );
  };

  // 삭제 액션일 때 라벨 색상 자동 설정
  useEffect(() => {
    if (isDeleteAction() && !component.style?.labelColor) {
      // 삭제 액션이고 라벨 색상이 설정되지 않은 경우 빨간색으로 자동 설정
      if (component.style) {
        component.style.labelColor = "#ef4444";
      } else {
        component.style = { labelColor: "#ef4444" };
      }
    }
  }, [component.componentConfig?.action?.type, component.config?.action?.type, component.webTypeConfig?.actionType]);

  // 컴포넌트 설정
  // 🔥 component.componentConfig도 병합해야 함 (화면 디자이너에서 저장된 설정)
  const componentConfig = {
    ...config,
    ...component.config,
    ...component.componentConfig, // 🔥 화면 디자이너에서 저장된 action 등 포함
  } as ButtonPrimaryConfig;

  // 🎨 동적 색상 설정 (webTypeConfig 우선, 레거시 style.labelColor 지원)
  const getButtonBackgroundColor = () => {
    // 1순위: webTypeConfig.backgroundColor (화면설정 모달에서 저장)
    if (component.webTypeConfig?.backgroundColor) {
      return component.webTypeConfig.backgroundColor;
    }
    // 2순위: componentConfig.backgroundColor
    if (componentConfig.backgroundColor) {
      return componentConfig.backgroundColor;
    }
    // 3순위: style.backgroundColor
    if (component.style?.backgroundColor) {
      return component.style.backgroundColor;
    }
    // 4순위: style.labelColor (레거시)
    if (component.style?.labelColor) {
      return component.style.labelColor;
    }
    // 기본값: 삭제 버튼이면 빨강, 아니면 파랑
    if (isDeleteAction()) {
      return "#ef4444"; // 빨간색 (Tailwind red-500)
    }
    return "#3b82f6"; // 파란색 (Tailwind blue-500)
  };

  const getButtonTextColor = () => {
    // 1순위: webTypeConfig.textColor (화면설정 모달에서 저장)
    if (component.webTypeConfig?.textColor) {
      return component.webTypeConfig.textColor;
    }
    // 2순위: componentConfig.textColor
    if (componentConfig.textColor) {
      return componentConfig.textColor;
    }
    // 3순위: style.color
    if (component.style?.color) {
      return component.style.color;
    }
    // 기본값: 흰색
    return "#ffffff";
  };

  const buttonColor = getButtonBackgroundColor();
  const buttonTextColor = getButtonTextColor();

  // 액션 설정 처리 - DB에서 문자열로 저장된 액션을 객체로 변환
  const processedConfig = { ...componentConfig };
  if (componentConfig.action && typeof componentConfig.action === "string") {
    const actionType = componentConfig.action as ButtonActionType;
    processedConfig.action = {
      ...DEFAULT_BUTTON_ACTIONS[actionType],
      type: actionType,
      // 🔥 제어관리 설정 추가 (webTypeConfig에서 가져옴)
      enableDataflowControl: component.webTypeConfig?.enableDataflowControl,
      dataflowConfig: component.webTypeConfig?.dataflowConfig,
      dataflowTiming: component.webTypeConfig?.dataflowTiming,
    };
  } else if (componentConfig.action && typeof componentConfig.action === "object") {
    // 🔥 이미 객체인 경우에도 제어관리 설정 추가
    processedConfig.action = {
      ...componentConfig.action,
      enableDataflowControl: component.webTypeConfig?.enableDataflowControl,
      dataflowConfig: component.webTypeConfig?.dataflowConfig,
      dataflowTiming: component.webTypeConfig?.dataflowTiming,
    };
  }

  // 스타일 계산
  // 🔧 사용자가 설정한 크기가 있으면 그대로 사용
  const componentStyle: React.CSSProperties = {
    ...component.style,
    ...style,
  };

  // 디자인 모드 스타일 (border 속성 분리하여 충돌 방지)
  if (isDesignMode) {
    componentStyle.borderWidth = "1px";
    componentStyle.borderStyle = "dashed";
    componentStyle.borderColor = isSelected ? "#3b82f6" : "#cbd5e1";
  }

  // 확인 다이얼로그가 필요한 액션 타입들
  const confirmationRequiredActions: ButtonActionType[] = ["save", "delete"];

  // 실제 액션 실행 함수
  const executeAction = async (actionConfig: any, context: ButtonActionContext) => {
    try {
      // 기존 토스트가 있다면 먼저 제거
      if (currentLoadingToastRef.current !== undefined) {
        toast.dismiss(currentLoadingToastRef.current);
        currentLoadingToastRef.current = undefined;
      }

      // 추가 안전장치: 모든 로딩 토스트 제거
      toast.dismiss();

      // UI 전환 액션 및 모달 액션은 로딩 토스트 표시하지 않음
      const silentActions = ["edit", "modal", "navigate", "excel_upload", "barcode_scan"];
      if (!silentActions.includes(actionConfig.type)) {
        currentLoadingToastRef.current = toast.loading(
          actionConfig.type === "save"
            ? "저장 중..."
            : actionConfig.type === "delete"
              ? "삭제 중..."
              : actionConfig.type === "submit"
                ? "제출 중..."
                : "처리 중...",
          {
            duration: Infinity, // 명시적으로 무한대로 설정
          },
        );
      }

      const success = await ButtonActionExecutor.executeAction(actionConfig, context);

      // 로딩 토스트 제거 (있는 경우에만)
      if (currentLoadingToastRef.current !== undefined) {
        toast.dismiss(currentLoadingToastRef.current);
        currentLoadingToastRef.current = undefined;
      }

      // 실패한 경우 오류 처리
      if (!success) {
        // UI 전환 액션 및 모달 액션은 에러도 조용히 처리 (모달 내부에서 자체 에러 표시)
        const silentErrorActions = ["edit", "modal", "navigate", "excel_upload", "barcode_scan"];
        if (silentErrorActions.includes(actionConfig.type)) {
          return;
        }
        // 기본 에러 메시지 결정
        const defaultErrorMessage =
          actionConfig.type === "save"
            ? "저장 중 오류가 발생했습니다."
            : actionConfig.type === "delete"
              ? "삭제 중 오류가 발생했습니다."
              : actionConfig.type === "submit"
                ? "제출 중 오류가 발생했습니다."
                : "처리 중 오류가 발생했습니다.";

        // 커스텀 메시지 사용 조건:
        // 1. 커스텀 메시지가 있고
        // 2. (액션 타입이 save이거나 OR 메시지에 "저장"이 포함되지 않은 경우)
        const useCustomMessage =
          actionConfig.errorMessage && (actionConfig.type === "save" || !actionConfig.errorMessage.includes("저장"));

        const errorMessage = useCustomMessage ? actionConfig.errorMessage : defaultErrorMessage;

        toast.error(errorMessage);
        return;
      }

      // 성공한 경우에만 성공 토스트 표시
      // save, delete, submit 액션에서만 성공 메시지 표시
      // 그 외 액션은 조용히 처리 (불필요한 "완료되었습니다" 토스트 방지)
      const successToastActions = ["save", "delete", "submit"];
      if (successToastActions.includes(actionConfig.type)) {
        // 기본 성공 메시지 결정
        const defaultSuccessMessage =
          actionConfig.type === "save"
            ? "저장되었습니다."
            : actionConfig.type === "delete"
              ? "삭제되었습니다."
              : "제출되었습니다.";

        // 커스텀 메시지 사용 조건:
        // 1. 커스텀 메시지가 있고
        // 2. (액션 타입이 save이거나 OR 메시지에 "저장"이 포함되지 않은 경우)
        const useCustomMessage =
          actionConfig.successMessage &&
          (actionConfig.type === "save" || !actionConfig.successMessage.includes("저장"));

        const successMessage = useCustomMessage ? actionConfig.successMessage : defaultSuccessMessage;

        toast.success(successMessage);
      }

      // 저장/수정 성공 시 자동 처리
      if (actionConfig.type === "save" || actionConfig.type === "edit") {
        // 1. 테이블 새로고침 이벤트 먼저 발송 (모달이 닫히기 전에)
        // V2 EventBus 사용 (레거시 어댑터가 자동으로 window 이벤트로도 브릿지)
        v2EventBus.emitSync(V2_EVENTS.TABLE_REFRESH, {
          tableName: context.tableName,
          target: "all",
        });

        // 2. 모달 닫기 (약간의 딜레이)
        setTimeout(() => {
          // EditModal 내부인지 확인 (isInModal prop 사용)
          const isInEditModal = (props as any).isInModal;

          if (isInEditModal) {
            v2EventBus.emitSync(V2_EVENTS.MODAL_CLOSE, {
              modalId: "edit-modal",
              reason: "save",
            });
          }

          // ScreenModal은 연속 등록 모드를 지원하므로 saveSuccessInModal 이벤트 발생
          v2EventBus.emitSync(V2_EVENTS.MODAL_SAVE_SUCCESS, {
            modalId: "screen-modal",
            savedData: context.formData || {},
            tableName: context.tableName || "",
          });
        }, 100);
      }
    } catch (error) {
      // 로딩 토스트 제거
      if (currentLoadingToastRef.current !== undefined) {
        toast.dismiss(currentLoadingToastRef.current);
        currentLoadingToastRef.current = undefined;
      }

      console.error("❌ 버튼 액션 실행 오류:", error);

      // 오류 토스트는 buttonActions.ts에서 이미 표시되므로 여기서는 제거
      // (중복 토스트 방지)
    }
  };

  // 이벤트 핸들러
  /**
   * transferData 액션 처리
   */
  const handleTransferDataAction = async (actionConfig: any) => {
    const dataTransferConfig = actionConfig.dataTransfer;

    if (!dataTransferConfig) {
      toast.error("데이터 전달 설정이 없습니다.");
      return;
    }

    if (!screenContext) {
      toast.error("화면 컨텍스트를 찾을 수 없습니다.");
      return;
    }

    try {
      // 1. 소스 컴포넌트에서 데이터 가져오기
      let sourceProvider: import("@/types/data-transfer").DataProvidable | undefined;

      const isAutoSource =
        !dataTransferConfig.sourceComponentId || dataTransferConfig.sourceComponentId === "__auto__";

      if (!isAutoSource) {
        sourceProvider = screenContext.getDataProvider(dataTransferConfig.sourceComponentId);
      }

      // 자동 탐색 모드이거나, 지정된 소스를 찾지 못한 경우
      // 현재 마운트된 DataProvider 중에서 table-list를 자동 탐색
      if (!sourceProvider) {
        if (!isAutoSource) {
          console.log(
            `⚠️ [ButtonPrimary] 지정된 소스 컴포넌트를 찾을 수 없음: ${dataTransferConfig.sourceComponentId}`,
          );
        }
        console.log("🔍 [ButtonPrimary] 현재 활성 DataProvider 자동 탐색...");

        const allProviders = screenContext.getAllDataProviders();

        // table-list 우선 탐색
        for (const [id, provider] of allProviders) {
          if (provider.componentType === "table-list") {
            sourceProvider = provider;
            console.log(`✅ [ButtonPrimary] 테이블 리스트 자동 발견: ${id}`);
            break;
          }
        }

        // table-list가 없으면 첫 번째 DataProvider 사용
        if (!sourceProvider && allProviders.size > 0) {
          const firstEntry = allProviders.entries().next().value;
          if (firstEntry) {
            sourceProvider = firstEntry[1];
            console.log(
              `✅ [ButtonPrimary] 첫 번째 DataProvider 사용: ${firstEntry[0]} (${sourceProvider.componentType})`,
            );
          }
        }

        if (!sourceProvider) {
          toast.error("데이터를 제공할 수 있는 컴포넌트를 찾을 수 없습니다.");
          return;
        }
      }

      const rawSourceData = sourceProvider.getSelectedData();

      // 🆕 배열이 아닌 경우 배열로 변환
      const sourceData = Array.isArray(rawSourceData) ? rawSourceData : rawSourceData ? [rawSourceData] : [];

      console.log("📦 소스 데이터:", { rawSourceData, sourceData, isArray: Array.isArray(rawSourceData) });

      if (!sourceData || sourceData.length === 0) {
        toast.warning("선택된 데이터가 없습니다.");
        return;
      }

      // 1.5. 추가 데이터 소스 처리 (예: 조건부 컨테이너의 카테고리 값)
      let additionalData: Record<string, any> = {};

      // 방법 1: additionalSources 설정에서 가져오기
      if (dataTransferConfig.additionalSources && Array.isArray(dataTransferConfig.additionalSources)) {
        for (const additionalSource of dataTransferConfig.additionalSources) {
          const additionalProvider = screenContext.getDataProvider(additionalSource.componentId);

          if (additionalProvider) {
            const additionalValues = additionalProvider.getSelectedData();

            if (additionalValues && additionalValues.length > 0) {
              const firstValue = additionalValues[0];

              if (additionalSource.fieldName) {
                additionalData[additionalSource.fieldName] =
                  firstValue[additionalSource.fieldName] || firstValue.condition || firstValue;
              } else {
                additionalData = { ...additionalData, ...firstValue };
              }

              console.log("📦 추가 데이터 수집 (additionalSources):", {
                sourceId: additionalSource.componentId,
                fieldName: additionalSource.fieldName,
                value: additionalData[additionalSource.fieldName || "all"],
              });
            }
          } else if (formData) {
            // DataProvider로 등록되지 않은 컴포넌트(v2-select 등)는 formData에서 값을 가져옴
            const comp = allComponents?.find((c: any) => c.id === additionalSource.componentId);
            const columnName =
              comp?.columnName ||
              comp?.componentConfig?.columnName ||
              comp?.overrides?.columnName;

            if (columnName && formData[columnName] !== undefined && formData[columnName] !== "") {
              const targetField = additionalSource.fieldName || columnName;
              additionalData[targetField] = formData[columnName];

              console.log("📦 추가 데이터 수집 (formData 폴백):", {
                sourceId: additionalSource.componentId,
                columnName,
                targetField,
                value: formData[columnName],
              });
            }
          }
        }
      }

      // 방법 2: formData에서 조건부 컨테이너 값 가져오기 (자동)
      // ConditionalSectionViewer가 __conditionalContainerValue, __conditionalContainerControlField를 formData에 포함시킴
      if (formData && formData.__conditionalContainerValue) {
        // includeConditionalValue 설정이 true이거나 설정이 없으면 자동 포함
        if (dataTransferConfig.includeConditionalValue !== false) {
          const conditionalValue = formData.__conditionalContainerValue;
          const conditionalLabel = formData.__conditionalContainerLabel;
          const controlField = formData.__conditionalContainerControlField; // 🆕 제어 필드명 직접 사용

          // 🆕 controlField가 있으면 그것을 필드명으로 사용 (자동 매핑!)
          if (controlField) {
            additionalData[controlField] = conditionalValue;
            console.log("📦 조건부 컨테이너 값 자동 매핑:", {
              controlField,
              value: conditionalValue,
              label: conditionalLabel,
            });
          } else {
            // controlField가 없으면 기존 방식: formData에서 같은 값을 가진 키 찾기
            for (const [key, value] of Object.entries(formData)) {
              if (value === conditionalValue && !key.startsWith("__")) {
                additionalData[key] = conditionalValue;
                console.log("📦 조건부 컨테이너 값 자동 포함:", {
                  fieldName: key,
                  value: conditionalValue,
                  label: conditionalLabel,
                });
                break;
              }
            }

            // 못 찾았으면 기본 필드명 사용
            if (!Object.keys(additionalData).some((k) => !k.startsWith("__"))) {
              additionalData["condition_type"] = conditionalValue;
              console.log("📦 조건부 컨테이너 값 (기본 필드명):", {
                fieldName: "condition_type",
                value: conditionalValue,
              });
            }
          }
        }
      }

      // 2. 검증
      const validation = dataTransferConfig.validation;
      if (validation) {
        if (validation.minSelection && sourceData.length < validation.minSelection) {
          toast.error(`최소 ${validation.minSelection}개 이상 선택해야 합니다.`);
          return;
        }
        if (validation.maxSelection && sourceData.length > validation.maxSelection) {
          toast.error(`최대 ${validation.maxSelection}개까지 선택할 수 있습니다.`);
          return;
        }
      }

      // 3. 확인 메시지
      if (dataTransferConfig.confirmBeforeTransfer) {
        const confirmMessage = dataTransferConfig.confirmMessage || `${sourceData.length}개 항목을 전달하시겠습니까?`;
        if (!window.confirm(confirmMessage)) {
          return;
        }
      }

      // 4. 매핑 규칙 결정: 멀티 테이블 매핑 또는 레거시 단일 매핑
      let effectiveMappingRules: any[] = dataTransferConfig.mappingRules || [];

      const sourceTableName = sourceProvider?.tableName;
      const multiTableMappings: Array<{ sourceTable: string; mappingRules: any[] }> =
        dataTransferConfig.multiTableMappings || [];

      if (multiTableMappings.length > 0 && sourceTableName) {
        const matchedGroup = multiTableMappings.find((g) => g.sourceTable === sourceTableName);
        if (matchedGroup) {
          effectiveMappingRules = matchedGroup.mappingRules || [];
          console.log(`✅ [ButtonPrimary] 멀티 테이블 매핑 적용: ${sourceTableName}`, effectiveMappingRules);
        } else {
          console.log(`⚠️ [ButtonPrimary] 소스 테이블 ${sourceTableName}에 대한 매핑 없음, 동일 필드명 자동 매핑`);
          effectiveMappingRules = [];
        }
      } else if (multiTableMappings.length > 0 && !sourceTableName) {
        console.log("⚠️ [ButtonPrimary] 소스 테이블 미감지, 첫 번째 매핑 그룹 사용");
        effectiveMappingRules = multiTableMappings[0]?.mappingRules || [];
      }

      const mappedData = sourceData.map((row) => {
        const mappedRow = applyMappingRules(row, effectiveMappingRules);

        return {
          ...mappedRow,
          ...additionalData,
        };
      });

      // 5. targetType / targetComponentId 기본값 및 자동 탐색
      const effectiveTargetType = dataTransferConfig.targetType || "component";
      let effectiveTargetComponentId = dataTransferConfig.targetComponentId;

      // targetComponentId가 없으면 현재 화면에서 DataReceiver 자동 탐색
      if (effectiveTargetType === "component" && !effectiveTargetComponentId) {
        console.log("🔍 [ButtonPrimary] 타겟 컴포넌트 자동 탐색...");
        const allReceivers = screenContext.getAllDataReceivers();

        // repeater 계열 우선 탐색
        for (const [id, receiver] of allReceivers) {
          if (
            receiver.componentType === "repeater-field-group" ||
            receiver.componentType === "v2-repeater" ||
            receiver.componentType === "repeater"
          ) {
            effectiveTargetComponentId = id;
            console.log(`✅ [ButtonPrimary] 리피터 자동 발견: ${id} (${receiver.componentType})`);
            break;
          }
        }

        // repeater가 없으면 소스가 아닌 첫 번째 DataReceiver 사용
        if (!effectiveTargetComponentId) {
          for (const [id, receiver] of allReceivers) {
            if (receiver.componentType === "table-list" || receiver.componentType === "data-table") {
              effectiveTargetComponentId = id;
              console.log(`✅ [ButtonPrimary] DataReceiver 자동 발견: ${id} (${receiver.componentType})`);
              break;
            }
          }
        }

        if (!effectiveTargetComponentId) {
          toast.error("데이터를 받을 수 있는 타겟 컴포넌트를 찾을 수 없습니다.");
          return;
        }
      }

      console.log("📦 데이터 전달:", {
        sourceData,
        mappedData,
        targetType: effectiveTargetType,
        targetComponentId: effectiveTargetComponentId,
        targetScreenId: dataTransferConfig.targetScreenId,
      });

      // 6. 타겟으로 데이터 전달
      if (effectiveTargetType === "component") {
        const targetReceiver = screenContext.getDataReceiver(effectiveTargetComponentId);

        const receiverConfig = {
          targetComponentId: effectiveTargetComponentId,
          targetComponentType: targetReceiver?.componentType || ("table" as const),
          mode: dataTransferConfig.mode || ("append" as const),
          mappingRules: dataTransferConfig.mappingRules || [],
        };

        if (!targetReceiver) {
          // 타겟이 아직 마운트되지 않은 경우 (조건부 레이어 등)
          // 버퍼에 저장하고 레이어 활성화 요청
          console.log(
            `⏳ [ButtonPrimary] 타겟 컴포넌트 미마운트, 대기열에 추가: ${effectiveTargetComponentId}`,
          );

          screenContext.addPendingTransfer({
            targetComponentId: effectiveTargetComponentId,
            data: mappedData,
            config: receiverConfig,
            timestamp: Date.now(),
            targetLayerId: dataTransferConfig.targetLayerId,
          });

          // 레이어 활성화 이벤트 발행 (page.tsx에서 수신)
          const activateEvent = new CustomEvent("activateLayerForComponent", {
            detail: {
              componentId: effectiveTargetComponentId,
              targetLayerId: dataTransferConfig.targetLayerId,
            },
          });
          window.dispatchEvent(activateEvent);

          toast.info(`타겟 레이어를 활성화하고 데이터 전달을 준비합니다...`);
          return;
        }

        await targetReceiver.receiveData(mappedData, receiverConfig);

        toast.success(`${sourceData.length}개 항목이 전달되었습니다.`);
      } else if (effectiveTargetType === "splitPanel") {
        // 🆕 분할 패널의 반대편 화면으로 전달
        if (!splitPanelContext) {
          toast.error("분할 패널 컨텍스트를 찾을 수 없습니다. 이 버튼이 분할 패널 내부에 있는지 확인하세요.");
          return;
        }

        // 🆕 useSplitPanelPosition 훅으로 위치 가져오기 (중첩된 화면에서도 작동)
        // screenId로 찾는 것은 직접 임베드된 화면에서만 작동하므로,
        // SplitPanelPositionProvider로 전달된 위치를 우선 사용
        const currentPosition =
          splitPanelPosition || (screenId ? splitPanelContext.getPositionByScreenId(screenId) : null);

        if (!currentPosition) {
          toast.error("분할 패널 내 위치를 확인할 수 없습니다. screenId: " + screenId);
          return;
        }

        console.log("📦 분할 패널 데이터 전달:", {
          currentPosition,
          splitPanelPositionFromHook: splitPanelPosition,
          screenId,
          leftScreenId: splitPanelContext.leftScreenId,
          rightScreenId: splitPanelContext.rightScreenId,
        });

        const result = await splitPanelContext.transferToOtherSide(
          currentPosition,
          mappedData,
          dataTransferConfig.targetComponentId, // 특정 컴포넌트 지정 (선택사항)
          dataTransferConfig.mode || "append",
        );

        if (result.success) {
          toast.success(result.message);
        } else {
          toast.error(result.message);
          return;
        }
      } else if (dataTransferConfig.targetType === "screen") {
        // 다른 화면으로 전달 (구현 예정)
        toast.info("다른 화면으로의 데이터 전달은 추후 구현 예정입니다.");
        return;
      } else {
        toast.success(`${sourceData.length}개 항목이 전달되었습니다.`);
      }

      // 6. 전달 후 정리
      if (dataTransferConfig.clearAfterTransfer) {
        sourceProvider.clearSelection();
      }
    } catch (error: any) {
      console.error("❌ 데이터 전달 실패:", error);
      toast.error(error.message || "데이터 전달 중 오류가 발생했습니다.");
    }
  };

  const handleClick = async (e: React.MouseEvent) => {
    e.stopPropagation();

    // 프리뷰 모드에서는 버튼 동작 차단
    if (isPreviewMode) {
      return;
    }

    // 디자인 모드에서는 기본 onClick만 실행
    if (isDesignMode) {
      onClick?.();
      return;
    }

    // 인터랙티브 모드에서 액션 실행
    if (isInteractive && processedConfig.action) {
      // transferData 액션 처리 (화면 컨텍스트 필요)
      if (processedConfig.action.type === "transferData") {
        await handleTransferDataAction(processedConfig.action);
        return;
      }

      // 🆕 선택된 데이터 우선순위:
      // 1. selectedRowsData (테이블에서 직접 선택)
      // 2. groupedData (부모창에서 모달로 전달된 데이터)
      // 3. modalDataStore (분할 패널 등에서 선택한 데이터)
      let effectiveSelectedRowsData = selectedRowsData;

      // groupedData가 있으면 우선 사용 (모달에서 부모 데이터 접근)
      if (
        (!effectiveSelectedRowsData || effectiveSelectedRowsData.length === 0) &&
        groupedData &&
        groupedData.length > 0
      ) {
        effectiveSelectedRowsData = groupedData;
      }

      // modalDataStore에서 선택된 데이터 가져오기 (분할 패널 등에서 선택한 데이터)
      // 단, 모달(modal) 액션은 신규 등록이므로 modalDataStore 데이터를 가져오지 않음
      // (다른 화면에서 선택한 데이터가 남아있을 수 있으므로)
      const shouldFetchFromModalDataStore =
        processedConfig.action.type !== "modal" &&
        (!effectiveSelectedRowsData || effectiveSelectedRowsData.length === 0) &&
        effectiveTableName;

      if (shouldFetchFromModalDataStore) {
        try {
          const { useModalDataStore } = await import("@/stores/modalDataStore");
          const dataRegistry = useModalDataStore.getState().dataRegistry;
          const modalData = dataRegistry[effectiveTableName];
          if (modalData && modalData.length > 0) {
            // modalDataStore는 {id, originalData, additionalData} 형태로 저장됨
            // originalData를 추출하여 실제 행 데이터를 가져옴
            effectiveSelectedRowsData = modalData.map((item: any) => {
              // originalData가 있으면 그것을 사용, 없으면 item 자체 사용 (하위 호환성)
              return item.originalData || item;
            });
          }
        } catch (error) {
          console.warn("modalDataStore 접근 실패:", error);
        }
      }

      // 삭제 액션인데 선택된 데이터가 없으면 경고 메시지 표시하고 중단
      const hasDataToDelete =
        (effectiveSelectedRowsData && effectiveSelectedRowsData.length > 0) ||
        (flowSelectedData && flowSelectedData.length > 0);

      if (processedConfig.action.type === "delete" && !hasDataToDelete) {
        toast.warning("삭제할 항목을 먼저 선택해주세요.");
        return;
      }

      // 🔧 모달 액션 시 선택 데이터 경고 제거
      // 이전에는 "신규 등록 시에는 테이블에서 선택된 항목을 해제해주세요" 경고를 표시했으나,
      // 다른 화면에서 선택한 데이터가 남아있는 경우 오탐이 발생하여 제거함.
      // 모달 화면 내부에서 필요 시 자체적으로 선택 데이터를 무시하도록 처리하면 됨.

      // 수정(edit) 액션 검증
      if (processedConfig.action.type === "edit") {
        // 선택된 데이터가 없으면 경고
        if (!effectiveSelectedRowsData || effectiveSelectedRowsData.length === 0) {
          toast.warning("수정할 항목을 선택해주세요.");
          return;
        }

        // groupByColumns 설정이 있으면 해당 컬럼 값이 유일한지 확인
        const groupByColumns = processedConfig.action.groupByColumns;
        if (groupByColumns && groupByColumns.length > 0 && effectiveSelectedRowsData.length > 1) {
          // 첫 번째 그룹핑 컬럼 기준으로 중복 체크 (예: order_no)
          const groupByColumn = groupByColumns[0];
          const uniqueValues = new Set(effectiveSelectedRowsData.map((row: any) => row[groupByColumn]).filter(Boolean));

          if (uniqueValues.size > 1) {
            // 컬럼명을 한글로 변환 (order_no -> 수주번호)
            const columnLabels: Record<string, string> = {
              order_no: "수주번호",
              shipment_no: "출하번호",
              purchase_no: "구매번호",
            };
            const columnLabel = columnLabels[groupByColumn] || groupByColumn;
            toast.warning(`${columnLabel} 하나만 선택해주세요. (현재 ${uniqueValues.size}개 선택됨)`);
            return;
          }
        }
      }

      // 🆕 모든 컴포넌트의 설정 수집 (parentDataMapping 등)
      const componentConfigs: Record<string, any> = {};
      if (allComponents && Array.isArray(allComponents)) {
        for (const comp of allComponents) {
          if (comp.id && comp.componentConfig) {
            componentConfigs[comp.id] = comp.componentConfig;
          }
        }
      }

      // 분할 패널 부모 데이터 가져오기 (우측 화면에서 저장 시 좌측 선택 데이터 포함)
      // 조건 완화: splitPanelContext가 있고 selectedLeftData가 있으면 가져옴
      // (탭 안에서도 분할 패널 컨텍스트에 접근 가능하도록)
      let splitPanelParentData: Record<string, any> | undefined;
      if (splitPanelContext) {
        // 우측 화면이거나, 탭 안의 화면(splitPanelPosition이 undefined)인 경우 모두 처리
        // 좌측 화면이 아닌 경우에만 부모 데이터 포함 (좌측에서 저장 시 자신의 데이터를 부모로 포함하면 안됨)
        if (splitPanelPosition !== "left") {
          splitPanelParentData = splitPanelContext.getMappedParentData();
        }
      }

      // 🆕 분할 패널 우측이면 여러 소스에서 formData를 병합
      // 우선순위: props.formData > screenContext.formData > splitPanelParentData
      const screenContextFormData = screenContext?.formData || {};
      const propsFormData = formData || {};

      // 병합: splitPanelParentData를 기본으로, props.formData, screenContext.formData 순으로 오버라이드
      // (일반 폼 필드는 props.formData, RepeaterFieldGroup은 screenContext.formData에 있음)
      let effectiveFormData = { ...propsFormData, ...screenContextFormData };

      // 분할 패널 우측이고 formData가 비어있으면 splitPanelParentData 사용
      if (splitPanelPosition === "right" && Object.keys(effectiveFormData).length === 0 && splitPanelParentData) {
        effectiveFormData = { ...splitPanelParentData };
      }

      const context: ButtonActionContext = {
        formData: effectiveFormData,
        originalData: originalData, // 🔧 빈 객체 대신 undefined 유지 (UPDATE 판단에 사용)
        screenId: effectiveScreenId, // 🆕 ScreenContext에서 가져온 값 사용
        tableName: effectiveTableName, // 🆕 ScreenContext에서 가져온 값 사용
        userId, // 🆕 사용자 ID
        userName, // 🆕 사용자 이름
        companyCode, // 🆕 회사 코드
        onFormDataChange,
        onRefresh,
        onClose,
        onFlowRefresh, // 플로우 새로고침 콜백 추가
        onSave: finalOnSave, // 🆕 EditModal의 handleSave 콜백 (props에서도 추출)
        // 테이블 선택된 행 정보 추가 (modalDataStore에서 가져온 데이터 우선)
        selectedRows,
        selectedRowsData: effectiveSelectedRowsData,
        // 테이블 정렬 정보 추가
        sortBy, // 🆕 정렬 컬럼
        sortOrder, // 🆕 정렬 방향
        columnOrder, // 🆕 컬럼 순서
        tableDisplayData, // 🆕 화면에 표시된 데이터
        // 🆕 같은 화면의 모든 컴포넌트 (TableList 자동 감지용)
        allComponents,
        // 플로우 선택된 데이터 정보 추가
        flowSelectedData,
        flowSelectedStepId,
        // 🆕 컴포넌트별 설정 (parentDataMapping 등)
        componentConfigs,
        // 🆕 분할 패널 부모 데이터 (좌측 화면에서 선택된 데이터)
        splitPanelParentData,
        // 🆕 분할 패널 컨텍스트 (quickInsert 등에서 좌측 패널 데이터 접근용)
        splitPanelContext: splitPanelContext
          ? {
              selectedLeftData: splitPanelContext.selectedLeftData,
              refreshRightPanel: splitPanelContext.refreshRightPanel,
            }
          : undefined,
      } as ButtonActionContext;

      // 확인이 필요한 액션인지 확인 (save/delete만 확인 다이얼로그 표시)
      if (confirmationRequiredActions.includes(processedConfig.action.type)) {
        // 확인 다이얼로그 표시
        setPendingAction({
          type: processedConfig.action.type,
          config: processedConfig.action,
          context,
        });
        setShowConfirmDialog(true);
      } else {
        // 확인이 필요하지 않은 액션은 바로 실행
        await executeAction(processedConfig.action, context);
      }
    } else {
      // 액션이 설정되지 않은 경우 기본 onClick 실행
      onClick?.();
    }
  };

  // 확인 다이얼로그에서 확인 버튼 클릭 시
  const handleConfirmAction = async () => {
    if (pendingAction) {
      await executeAction(pendingAction.config, pendingAction.context);
    }
    setShowConfirmDialog(false);
    setPendingAction(null);
  };

  // 확인 다이얼로그에서 취소 버튼 클릭 시
  const handleCancelAction = () => {
    setShowConfirmDialog(false);
    setPendingAction(null);
  };

  // DOM에 전달하면 안 되는 React-specific props 필터링
  const {
    selectedScreen,
    onZoneComponentDrop,
    onZoneClick,
    componentConfig: _componentConfig,
    component: _component,
    isSelected: _isSelected,
    onClick: _onClick,
    onDragStart: _onDragStart,
    onDragEnd: _onDragEnd,
    size: _size,
    position: _position,
    style: _style,
    screenId: _screenId,
    tableName: _tableName,
    onRefresh: _onRefresh,
    onClose: _onClose,
    selectedRows: _selectedRows,
    selectedRowsData: _selectedRowsData,
    onSelectedRowsChange: _onSelectedRowsChange,
    flowSelectedData: _flowSelectedData, // 플로우 선택 데이터 필터링
    flowSelectedStepId: _flowSelectedStepId, // 플로우 선택 스텝 ID 필터링
    onFlowRefresh: _onFlowRefresh, // 플로우 새로고침 콜백 필터링
    originalData: _originalData, // 부분 업데이트용 원본 데이터 필터링
    _originalData: __originalData, // DOM 필터링
    _initialData: __initialData, // DOM 필터링
    _groupedData: __groupedData, // DOM 필터링
    refreshKey: _refreshKey, // 필터링 추가
    isInModal: _isInModal, // 필터링 추가
    mode: _mode, // 필터링 추가
    ...domProps
  } = props;

  // 다이얼로그 메시지 생성
  const getConfirmMessage = () => {
    if (!pendingAction) return "";

    const customMessage = pendingAction.config.confirmMessage;
    if (customMessage) return customMessage;

    switch (pendingAction.type) {
      case "save":
        return "변경사항을 저장하시겠습니까?";
      case "delete":
        return "정말로 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.";
      case "submit":
        return "제출하시겠습니까?";
      default:
        return "이 작업을 실행하시겠습니까?";
    }
  };

  const getConfirmTitle = () => {
    if (!pendingAction) return "";

    switch (pendingAction.type) {
      case "save":
        return "저장 확인";
      case "delete":
        return "삭제 확인";
      case "submit":
        return "제출 확인";
      default:
        return "작업 확인";
    }
  };

  // DOM 안전한 props만 필터링
  const safeDomProps = filterDOMProps(domProps);

  // 🆕 플로우 단계별 표시 제어
  if (!shouldShowButton) {
    // 레이아웃 동작에 따라 다르게 처리
    if (flowConfig?.layoutBehavior === "preserve-position") {
      // 위치 유지 (빈 공간, display: none)
      return <div style={{ display: "none" }} />;
    } else {
      // 완전히 렌더링하지 않음 (auto-compact, 빈 공간 제거)
      return null;
    }
  }

  // 모달 내 저장 버튼: 필수 필드 미입력 시 비활성화
  const isInModalContext = (props as any).isInModal === true;
  const isSaveAction = processedConfig.action?.type === "save";
  const isRequiredFieldsMissing = isSaveAction && isInModalContext && allComponents
    ? !checkAllRequiredFieldsFilled(allComponents, formData || {})
    : false;

  // 최종 비활성화 상태 (설정 + 조건부 비활성화 + 행 선택 필수 + 필수 필드 미입력)
  const finalDisabled =
    componentConfig.disabled || isOperationButtonDisabled || isRowSelectionDisabled || statusLoading || isRequiredFieldsMissing;

  // 공통 버튼 스타일
  // 🔧 component.style에서 background/backgroundColor 충돌 방지 (width/height는 허용)
  const userStyle = component.style
    ? Object.fromEntries(
        Object.entries(component.style).filter(([key]) => !["background", "backgroundColor"].includes(key)),
      )
    : {};

  // 🔧 사용자가 설정한 크기 우선 사용, 없으면 100%
  const buttonWidth = component.size?.width ? `${component.size.width}px` : style?.width || "100%";
  const buttonHeight = component.size?.height ? `${component.size.height}px` : style?.height || "100%";

  const buttonElementStyle: React.CSSProperties = {
    width: buttonWidth,
    height: buttonHeight,
    minHeight: "32px", // 🔧 최소 높이를 32px로 줄임
    // 🔧 커스텀 테두리 스타일 (StyleEditor에서 설정한 값 우선)
    border: style?.border || (style?.borderWidth ? undefined : "none"),
    borderWidth: style?.borderWidth || undefined,
    borderStyle: (style?.borderStyle as React.CSSProperties["borderStyle"]) || undefined,
    borderColor: style?.borderColor || undefined,
    borderRadius: style?.borderRadius || "0.5rem",
    backgroundColor: finalDisabled ? "#e5e7eb" : buttonColor,
    color: finalDisabled ? "#9ca3af" : (style?.color || buttonTextColor), // 🔧 StyleEditor 텍스트 색상도 지원
    // 🔧 크기 설정 적용 (sm/md/lg), StyleEditor fontSize 우선
    fontSize: style?.fontSize || (componentConfig.size === "sm" ? "0.75rem" : componentConfig.size === "lg" ? "1rem" : "0.875rem"),
    fontWeight: style?.fontWeight || "600",
    cursor: finalDisabled ? "not-allowed" : "pointer",
    outline: "none",
    boxSizing: "border-box",
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    // 🔧 크기에 따른 패딩 조정
    padding: componentConfig.size === "sm" ? "0 0.75rem" : componentConfig.size === "lg" ? "0 1.25rem" : "0 1rem",
    margin: "0",
    lineHeight: "1.25",
    boxShadow: finalDisabled ? "none" : "0 1px 2px 0 rgba(0, 0, 0, 0.05)",
    // 디자인 모드와 인터랙티브 모드 모두에서 사용자 스타일 적용 (width/height/background 제외)
    ...userStyle,
  };

  // 버튼 텍스트 결정 (다양한 소스에서 가져옴)
  // "기본 버튼"은 컴포넌트 생성 시 기본값이므로 무시
  const labelValue = component.label === "기본 버튼" ? undefined : component.label;

  // 액션 타입에 따른 기본 텍스트 (modal 액션과 동일하게)
  const actionType = processedConfig.action?.type || component.componentConfig?.action?.type;
  const actionDefaultText: Record<string, string> = {
    save: "저장",
    delete: "삭제",
    modal: "등록",
    edit: "수정",
    copy: "복사",
    close: "닫기",
    cancel: "취소",
  };

  const buttonContent =
    processedConfig.text ||
    component.webTypeConfig?.text ||
    component.componentConfig?.text ||
    component.config?.text ||
    component.style?.labelText ||
    labelValue ||
    actionDefaultText[actionType as string] ||
    "버튼";

  return (
    <>
      <div style={componentStyle} className={className} {...safeDomProps}>
        {isDesignMode ? (
          // 디자인 모드: div로 렌더링하여 선택 가능하게 함
          <div
            className="transition-colors duration-150 hover:opacity-90"
            style={buttonElementStyle}
            onClick={handleClick}
          >
            {buttonContent}
          </div>
        ) : (
          // 일반 모드: button으로 렌더링
          <button
            type={componentConfig.actionType || "button"}
            disabled={finalDisabled}
            title={isRequiredFieldsMissing ? "필수 입력 항목을 모두 채워주세요" : undefined}
            className="transition-colors transition-transform duration-150 hover:opacity-90 active:scale-95"
            style={buttonElementStyle}
            onClick={handleClick}
            onDragStart={onDragStart}
            onDragEnd={onDragEnd}
          >
            {buttonContent}
          </button>
        )}
      </div>

      {/* 확인 다이얼로그 */}
      <AlertDialog open={showConfirmDialog} onOpenChange={setShowConfirmDialog}>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>{getConfirmTitle()}</AlertDialogTitle>
            <AlertDialogDescription>{getConfirmMessage()}</AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel onClick={handleCancelAction}>취소</AlertDialogCancel>
            <AlertDialogAction onClick={handleConfirmAction}>
              {pendingAction?.type === "save"
                ? "저장"
                : pendingAction?.type === "delete"
                  ? "삭제"
                  : pendingAction?.type === "submit"
                    ? "제출"
                    : "확인"}
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    </>
  );
};

/**
 * ButtonPrimary 래퍼 컴포넌트
 * V2 ErrorBoundary로 감싸서 에러 격리 제공
 */
export const ButtonPrimaryWrapper: React.FC<ButtonPrimaryComponentProps> = (props) => {
  return (
    <V2ErrorBoundary
      componentId={props.component?.id || `button-${Date.now()}`}
      componentType="v2-button-primary"
      fallbackStyle="minimal"
      recoverable={true}
    >
      <ButtonPrimaryComponent {...props} />
    </V2ErrorBoundary>
  );
};
