"use client";

import React, { useState, useEffect, useMemo, useCallback } from "react";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Switch } from "@/components/ui/switch";
import { Checkbox } from "@/components/ui/checkbox";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import {
  Check,
  ChevronsUpDown,
  Search,
  Plus,
  X,
  ChevronUp,
  ChevronDown,
  Type,
  Database,
  Info,
} from "lucide-react";
import { cn } from "@/lib/utils";
import { ComponentData } from "@/types/screen";
import { apiClient } from "@/lib/api/client";
import { QuickInsertConfigSection } from "../QuickInsertConfigSection";
import { getApprovalDefinitions, type ApprovalDefinition } from "@/lib/api/approval";
import type { ButtonTabProps, TitleBlock, ScreenOption } from "./types";

/** 액션 탭: 액션 유형별 상세 설정 (모달/이동/엑셀/결재/이벤트 등) */
export const ActionTab: React.FC<ButtonTabProps> = ({
  component,
  onUpdateProperty,
  allComponents,
  currentTableName,
  currentScreenCompanyCode,
}) => {
  const config = component.componentConfig || {};

  const [localInputs, setLocalInputs] = useState({
    actionType: String(config.action?.type || "save"),
    modalTitle: String(config.action?.modalTitle || ""),
    modalDescription: String(config.action?.modalDescription || ""),
    editModalTitle: String(config.action?.editModalTitle || ""),
    editModalDescription: String(config.action?.editModalDescription || ""),
    targetUrl: String(config.action?.targetUrl || ""),
    groupByColumn: String(config.action?.groupByColumns?.[0] || ""),
  });
  const [screens, setScreens] = useState<ScreenOption[]>([]);
  const [screensLoading, setScreensLoading] = useState(false);
  const [modalScreenOpen, setModalScreenOpen] = useState(false);
  const [navScreenOpen, setNavScreenOpen] = useState(false);
  const [modalSearchTerm, setModalSearchTerm] = useState("");
  const [navSearchTerm, setNavSearchTerm] = useState("");

  // 테이블 컬럼 목록 상태
  const [tableColumns, setTableColumns] = useState<string[]>([]);
  const [columnsLoading, setColumnsLoading] = useState(false);
  const [displayColumnOpen, setDisplayColumnOpen] = useState(false);
  const [displayColumnSearch, setDisplayColumnSearch] = useState("");

  // 🆕 제목 블록 빌더 상태
  const [titleBlocks, setTitleBlocks] = useState<TitleBlock[]>([]);
  const [availableTables, setAvailableTables] = useState<Array<{ name: string; label: string }>>([]); // 시스템의 모든 테이블 목록
  const [tableColumnsMap, setTableColumnsMap] = useState<Record<string, Array<{ name: string; label: string }>>>({});
  const [blockTableSearches, setBlockTableSearches] = useState<Record<string, string>>({}); // 블록별 테이블 검색어
  const [blockColumnSearches, setBlockColumnSearches] = useState<Record<string, string>>({}); // 블록별 컬럼 검색어
  const [blockTablePopoverOpen, setBlockTablePopoverOpen] = useState<Record<string, boolean>>({}); // 블록별 테이블 Popover 열림 상태
  const [blockColumnPopoverOpen, setBlockColumnPopoverOpen] = useState<Record<string, boolean>>({}); // 블록별 컬럼 Popover 열림 상태

  // 🆕 데이터 전달 필드 매핑용 상태 (멀티 테이블 매핑 지원)
  const [mappingSourceColumnsMap, setMappingSourceColumnsMap] = useState<
    Record<string, Array<{ name: string; label: string }>>
  >({});
  const [mappingTargetColumns, setMappingTargetColumns] = useState<Array<{ name: string; label: string }>>([]);
  const [mappingSourcePopoverOpen, setMappingSourcePopoverOpen] = useState<Record<string, boolean>>({});
  const [mappingTargetPopoverOpen, setMappingTargetPopoverOpen] = useState<Record<string, boolean>>({});
  const [mappingSourceSearch, setMappingSourceSearch] = useState<Record<string, string>>({});
  const [mappingTargetSearch, setMappingTargetSearch] = useState<Record<string, string>>({});
  const [activeMappingGroupIndex, setActiveMappingGroupIndex] = useState(0);

  // 🆕 openModalWithData 전용 필드 매핑 상태
  const [modalSourceColumns, setModalSourceColumns] = useState<Array<{ name: string; label: string }>>([]);
  const [modalTargetColumns, setModalTargetColumns] = useState<Array<{ name: string; label: string }>>([]);
  const [modalSourcePopoverOpen, setModalSourcePopoverOpen] = useState<Record<number, boolean>>({});
  const [modalTargetPopoverOpen, setModalTargetPopoverOpen] = useState<Record<number, boolean>>({});

  // 결재 유형 목록 상태
  const [approvalDefinitions, setApprovalDefinitions] = useState<ApprovalDefinition[]>([]);
  const [approvalDefinitionsLoading, setApprovalDefinitionsLoading] = useState(false);

  // 🆕 그룹화 컬럼 선택용 상태
  const [currentTableColumns, setCurrentTableColumns] = useState<Array<{ name: string; label: string }>>([]);
  const [groupByColumnOpen, setGroupByColumnOpen] = useState(false);
  const [groupByColumnSearch, setGroupByColumnSearch] = useState("");
  const [modalSourceSearch, setModalSourceSearch] = useState<Record<number, string>>({});
  const [modalTargetSearch, setModalTargetSearch] = useState<Record<number, string>>({});

  // 🆕 modal 액션용 필드 매핑 상태
  const [modalActionSourceTable, setModalActionSourceTable] = useState<string | null>(null);
  const [modalActionTargetTable, setModalActionTargetTable] = useState<string | null>(null);
  const [modalActionSourceColumns, setModalActionSourceColumns] = useState<Array<{ name: string; label: string }>>([]);
  const [modalActionTargetColumns, setModalActionTargetColumns] = useState<Array<{ name: string; label: string }>>([]);
  const [modalActionFieldMappings, setModalActionFieldMappings] = useState<
    Array<{ sourceField: string; targetField: string }>
  >([]);
  const [modalFieldMappingSourceOpen, setModalFieldMappingSourceOpen] = useState<Record<number, boolean>>({});
  const [modalFieldMappingTargetOpen, setModalFieldMappingTargetOpen] = useState<Record<number, boolean>>({});
  const [modalFieldMappingSourceSearch, setModalFieldMappingSourceSearch] = useState<Record<number, string>>({});
  const [modalFieldMappingTargetSearch, setModalFieldMappingTargetSearch] = useState<Record<number, string>>({});
  // 컴포넌트 prop 변경 시 로컬 상태 동기화 (Input만)
  useEffect(() => {
    const latestConfig = component.componentConfig || {};
    const latestAction = latestConfig.action || {};

    setLocalInputs({
      actionType: String(latestAction.type || "save"),
      modalTitle: String(latestAction.modalTitle || ""),
      modalDescription: String(latestAction.modalDescription || ""),
      editModalTitle: String(latestAction.editModalTitle || ""),
      editModalDescription: String(latestAction.editModalDescription || ""),
      targetUrl: String(latestAction.targetUrl || ""),
      groupByColumn: String(latestAction.groupByColumns?.[0] || ""),
    });

    // 🆕 제목 블록 초기화
    if (latestAction.modalTitleBlocks && latestAction.modalTitleBlocks.length > 0) {
      setTitleBlocks(latestAction.modalTitleBlocks);
    } else {
      // 기본값: 빈 배열
      setTitleBlocks([]);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [component.id, component.componentConfig?.action?.type]);

  // 🆕 제목 블록 핸들러
  const addTextBlock = () => {
    const newBlock: TitleBlock = {
      id: `text-${Date.now()}`,
      type: "text",
      value: "",
    };
    const updatedBlocks = [...titleBlocks, newBlock];
    setTitleBlocks(updatedBlocks);
    onUpdateProperty("componentConfig.action.modalTitleBlocks", updatedBlocks);
  };

  const addFieldBlock = () => {
    const newBlock: TitleBlock = {
      id: `field-${Date.now()}`,
      type: "field",
      value: "",
      tableName: "",
      label: "",
    };
    const updatedBlocks = [...titleBlocks, newBlock];
    setTitleBlocks(updatedBlocks);
    onUpdateProperty("componentConfig.action.modalTitleBlocks", updatedBlocks);
  };

  const updateBlock = (id: string, updates: Partial<TitleBlock>) => {
    const updatedBlocks = titleBlocks.map((block) => (block.id === id ? { ...block, ...updates } : block));
    setTitleBlocks(updatedBlocks);
    onUpdateProperty("componentConfig.action.modalTitleBlocks", updatedBlocks);
  };

  const removeBlock = (id: string) => {
    const updatedBlocks = titleBlocks.filter((block) => block.id !== id);
    setTitleBlocks(updatedBlocks);
    onUpdateProperty("componentConfig.action.modalTitleBlocks", updatedBlocks);
  };

  const moveBlockUp = (id: string) => {
    const index = titleBlocks.findIndex((b) => b.id === id);
    if (index <= 0) return;
    const newBlocks = [...titleBlocks];
    [newBlocks[index - 1], newBlocks[index]] = [newBlocks[index], newBlocks[index - 1]];
    setTitleBlocks(newBlocks);
    onUpdateProperty("componentConfig.action.modalTitleBlocks", newBlocks);
  };

  const moveBlockDown = (id: string) => {
    const index = titleBlocks.findIndex((b) => b.id === id);
    if (index < 0 || index >= titleBlocks.length - 1) return;
    const newBlocks = [...titleBlocks];
    [newBlocks[index], newBlocks[index + 1]] = [newBlocks[index + 1], newBlocks[index]];
    setTitleBlocks(newBlocks);
    onUpdateProperty("componentConfig.action.modalTitleBlocks", newBlocks);
  };

  // 🆕 제목 미리보기 생성
  const generateTitlePreview = (): string => {
    if (titleBlocks.length === 0) return "(제목 없음)";
    return titleBlocks
      .map((block) => {
        if (block.type === "text") {
          return block.value || "(텍스트)";
        } else {
          return block.label || block.value || "(필드)";
        }
      })
      .join("");
  };

  // 🆕 시스템의 모든 테이블 목록 로드
  useEffect(() => {
    const fetchAllTables = async () => {
      try {
        const response = await apiClient.get("/table-management/tables");

        if (response.data.success && response.data.data) {
          const tables = response.data.data.map((table: any) => ({
            name: table.tableName,
            label: table.displayName || table.tableName,
          }));
          setAvailableTables(tables);
        }
      } catch (error) {
        console.error("테이블 목록 로드 실패:", error);
      }
    };

    fetchAllTables();
  }, []);

  // 🆕 특정 테이블의 컬럼 로드
  const loadTableColumns = async (tableName: string) => {
    if (!tableName || tableColumnsMap[tableName]) return;

    try {
      const response = await apiClient.get(`/table-management/tables/${tableName}/columns`);
      console.log(`📥 테이블 ${tableName} 컬럼 응답:`, response.data);

      if (response.data.success) {
        // data가 배열인지 확인
        let columnData = response.data.data;

        // data.columns 형태일 수도 있음
        if (!Array.isArray(columnData) && columnData?.columns) {
          columnData = columnData.columns;
        }

        // data.data 형태일 수도 있음
        if (!Array.isArray(columnData) && columnData?.data) {
          columnData = columnData.data;
        }

        if (Array.isArray(columnData)) {
          const columns = columnData.map((col: any) => {
            const name = col.name || col.columnName;
            const label = col.displayName || col.label || col.columnLabel || name;
            console.log(`  - 컬럼: ${name} → "${label}"`);
            return { name, label };
          });
          setTableColumnsMap((prev) => ({ ...prev, [tableName]: columns }));
          console.log(`✅ 테이블 ${tableName} 컬럼 로드 성공:`, columns.length, "개");
        } else {
          console.error("❌ 컬럼 데이터가 배열이 아닙니다:", columnData);
        }
      }
    } catch (error) {
      console.error("컬럼 로드 실패:", error);
    }
  };

  // 멀티 테이블 매핑: 소스/타겟 테이블 컬럼 로드
  const loadMappingColumns = useCallback(async (tableName: string): Promise<Array<{ name: string; label: string }>> => {
    try {
      const response = await apiClient.get(`/table-management/tables/${tableName}/columns`);
      if (response.data.success) {
        let columnData = response.data.data;
        if (!Array.isArray(columnData) && columnData?.columns) columnData = columnData.columns;
        if (!Array.isArray(columnData) && columnData?.data) columnData = columnData.data;

        if (Array.isArray(columnData)) {
          return columnData.map((col: any) => ({
            name: col.name || col.columnName,
            label: col.displayName || col.label || col.columnLabel || col.name || col.columnName,
          }));
        }
      }
    } catch (error) {
      console.error(`테이블 ${tableName} 컬럼 로드 실패:`, error);
    }
    return [];
  }, []);

  useEffect(() => {
    const multiTableMappings: Array<{ sourceTable: string }> = config.action?.dataTransfer?.multiTableMappings || [];
    const legacySourceTable = config.action?.dataTransfer?.sourceTable;
    const targetTable = config.action?.dataTransfer?.targetTable;

    const loadAll = async () => {
      const sourceTableNames = multiTableMappings.map((m) => m.sourceTable).filter(Boolean);
      if (legacySourceTable && !sourceTableNames.includes(legacySourceTable)) {
        sourceTableNames.push(legacySourceTable);
      }

      const newMap: Record<string, Array<{ name: string; label: string }>> = {};
      for (const tbl of sourceTableNames) {
        if (!mappingSourceColumnsMap[tbl]) {
          newMap[tbl] = await loadMappingColumns(tbl);
        }
      }
      if (Object.keys(newMap).length > 0) {
        setMappingSourceColumnsMap((prev) => ({ ...prev, ...newMap }));
      }

      if (targetTable && mappingTargetColumns.length === 0) {
        const cols = await loadMappingColumns(targetTable);
        setMappingTargetColumns(cols);
      }
    };

    loadAll();
  }, [
    config.action?.dataTransfer?.multiTableMappings,
    config.action?.dataTransfer?.sourceTable,
    config.action?.dataTransfer?.targetTable,
    loadMappingColumns,
  ]);

  // 🆕 modal 액션: 대상 화면 테이블 조회 및 필드 매핑 로드
  useEffect(() => {
    const actionType = config.action?.type;
    if (actionType !== "modal") return;

    const autoDetect = config.action?.autoDetectDataSource;
    if (!autoDetect) {
      // 데이터 전달이 비활성화되면 상태 초기화
      setModalActionSourceTable(null);
      setModalActionTargetTable(null);
      setModalActionSourceColumns([]);
      setModalActionTargetColumns([]);
      return;
    }

    const targetScreenId = config.action?.targetScreenId;
    if (!targetScreenId) return;

    const loadModalActionMappingData = async () => {
      // 1. 소스 테이블 감지 (현재 화면)
      let sourceTableName: string | null = currentTableName || null;

      // allComponents에서 분할패널/테이블리스트/통합목록 감지
      for (const comp of allComponents) {
        const compType = comp.componentType || (comp as any).componentConfig?.type;
        const compConfig = (comp as any).componentConfig || {};

        if (compType === "split-panel-layout" || compType === "screen-split-panel") {
          sourceTableName = compConfig.leftPanel?.tableName || compConfig.tableName || null;
          if (sourceTableName) break;
        }
        if (compType === "table-list") {
          sourceTableName = compConfig.tableName || compConfig.selectedTable || null;
          if (sourceTableName) break;
        }
        if (compType === "v2-list") {
          sourceTableName = compConfig.dataSource?.table || compConfig.tableName || null;
          if (sourceTableName) break;
        }
      }

      setModalActionSourceTable(sourceTableName);

      // 2. 대상 화면의 테이블 조회
      let targetTableName: string | null = null;
      try {
        const screenResponse = await apiClient.get(`/screen-management/screens/${targetScreenId}`);
        if (screenResponse.data.success && screenResponse.data.data) {
          targetTableName = screenResponse.data.data.tableName || null;
        } else if (screenResponse.data?.tableName) {
          // 직접 데이터 반환 형식인 경우
          targetTableName = screenResponse.data.tableName || null;
        }
      } catch (error) {
        console.error("대상 화면 정보 로드 실패:", error);
      }

      setModalActionTargetTable(targetTableName);

      // 3. 소스 테이블 컬럼 로드
      if (sourceTableName) {
        try {
          const response = await apiClient.get(`/table-management/tables/${sourceTableName}/columns`);
          if (response.data.success) {
            let columnData = response.data.data;
            if (!Array.isArray(columnData) && columnData?.columns) columnData = columnData.columns;
            if (!Array.isArray(columnData) && columnData?.data) columnData = columnData.data;

            if (Array.isArray(columnData)) {
              const columns = columnData.map((col: any) => ({
                name: col.name || col.columnName,
                label: col.displayName || col.label || col.columnLabel || col.name || col.columnName,
              }));
              setModalActionSourceColumns(columns);
            }
          }
        } catch (error) {
          console.error("소스 테이블 컬럼 로드 실패:", error);
        }
      }

      // 4. 대상 테이블 컬럼 로드
      if (targetTableName) {
        try {
          const response = await apiClient.get(`/table-management/tables/${targetTableName}/columns`);
          if (response.data.success) {
            let columnData = response.data.data;
            if (!Array.isArray(columnData) && columnData?.columns) columnData = columnData.columns;
            if (!Array.isArray(columnData) && columnData?.data) columnData = columnData.data;

            if (Array.isArray(columnData)) {
              const columns = columnData.map((col: any) => ({
                name: col.name || col.columnName,
                label: col.displayName || col.label || col.columnLabel || col.name || col.columnName,
              }));
              setModalActionTargetColumns(columns);
            }
          }
        } catch (error) {
          console.error("대상 테이블 컬럼 로드 실패:", error);
        }
      }

      // 5. 기존 필드 매핑 로드 또는 자동 매핑 생성
      const existingMappings = config.action?.fieldMappings || [];
      if (existingMappings.length > 0) {
        setModalActionFieldMappings(existingMappings);
      } else if (sourceTableName && targetTableName && sourceTableName === targetTableName) {
        // 테이블이 같으면 자동 매핑 (동일 컬럼명)
        setModalActionFieldMappings([]); // 빈 배열 = 자동 매핑
      }
    };

    loadModalActionMappingData();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [
    config.action?.type,
    config.action?.autoDetectDataSource,
    config.action?.targetScreenId,
    currentTableName,
    allComponents,
  ]);

  // 🆕 현재 테이블 컬럼 로드 (그룹화 컬럼 선택용)
  useEffect(() => {
    if (!currentTableName) return;

    const loadCurrentTableColumns = async () => {
      try {
        const response = await apiClient.get(`/table-management/tables/${currentTableName}/columns`);
        if (response.data.success) {
          let columnData = response.data.data;
          if (!Array.isArray(columnData) && columnData?.columns) columnData = columnData.columns;
          if (!Array.isArray(columnData) && columnData?.data) columnData = columnData.data;

          if (Array.isArray(columnData)) {
            const columns = columnData.map((col: any) => ({
              name: col.name || col.columnName,
              label: col.displayName || col.label || col.columnLabel || col.name || col.columnName,
            }));
            setCurrentTableColumns(columns);
          }
        }
      } catch (error) {
        console.error("현재 테이블 컬럼 로드 실패:", error);
      }
    };

    loadCurrentTableColumns();
  }, [currentTableName]);

  // 🆕 openModalWithData 소스/타겟 테이블 컬럼 로드
  useEffect(() => {
    const actionType = config.action?.type;
    if (actionType !== "openModalWithData") return;

    const loadModalMappingColumns = async () => {
      // 소스 테이블: 현재 화면의 분할 패널 또는 테이블에서 감지
      let sourceTableName: string | null = null;

      console.log("[openModalWithData] 컬럼 로드 시작:", {
        allComponentsCount: allComponents.length,
        currentTableName,
        targetScreenId: config.action?.targetScreenId,
      });

      // 모든 컴포넌트 타입 로그
      allComponents.forEach((comp, idx) => {
        const compType = comp.componentType || (comp as any).componentConfig?.type;
        console.log(
          `  [${idx}] componentType: ${compType}, tableName: ${(comp as any).componentConfig?.tableName || (comp as any).componentConfig?.leftPanel?.tableName || "N/A"}`,
        );
      });

      for (const comp of allComponents) {
        const compType = comp.componentType || (comp as any).componentConfig?.type;
        const compConfig = (comp as any).componentConfig || {};

        // 분할 패널 타입들 (다양한 경로에서 테이블명 추출)
        if (compType === "split-panel-layout" || compType === "screen-split-panel") {
          sourceTableName = compConfig?.leftPanel?.tableName || compConfig?.leftTableName || compConfig?.tableName;
          if (sourceTableName) {
            console.log(`✅ [openModalWithData] split-panel-layout에서 소스 테이블 감지: ${sourceTableName}`);
            break;
          }
        }

        // split-panel-layout2 타입 (새로운 분할 패널)
        if (compType === "split-panel-layout2") {
          sourceTableName = compConfig?.leftPanel?.tableName || compConfig?.tableName || compConfig?.leftTableName;
          if (sourceTableName) {
            console.log(`✅ [openModalWithData] split-panel-layout2에서 소스 테이블 감지: ${sourceTableName}`);
            break;
          }
        }

        // 테이블 리스트 타입
        if (compType === "table-list") {
          sourceTableName = compConfig?.tableName;
          if (sourceTableName) {
            console.log(`✅ [openModalWithData] table-list에서 소스 테이블 감지: ${sourceTableName}`);
            break;
          }
        }

        // 🆕 모든 컴포넌트에서 tableName 찾기 (폴백)
        if (!sourceTableName && compConfig?.tableName) {
          sourceTableName = compConfig.tableName;
          console.log(`✅ [openModalWithData] ${compType}에서 소스 테이블 감지 (폴백): ${sourceTableName}`);
          break;
        }
      }

      // 여전히 없으면 currentTableName 사용 (화면 레벨 테이블명)
      if (!sourceTableName && currentTableName) {
        sourceTableName = currentTableName;
        console.log(`✅ [openModalWithData] currentTableName에서 소스 테이블 사용: ${sourceTableName}`);
      }

      if (!sourceTableName) {
        console.warn("[openModalWithData] 소스 테이블을 찾을 수 없습니다.");
      }

      // 소스 테이블 컬럼 로드
      if (sourceTableName) {
        try {
          const response = await apiClient.get(`/table-management/tables/${sourceTableName}/columns`);
          if (response.data.success) {
            let columnData = response.data.data;
            if (!Array.isArray(columnData) && columnData?.columns) columnData = columnData.columns;
            if (!Array.isArray(columnData) && columnData?.data) columnData = columnData.data;

            if (Array.isArray(columnData)) {
              const columns = columnData.map((col: any) => ({
                name: col.name || col.columnName || col.column_name,
                label:
                  col.displayName ||
                  col.label ||
                  col.columnLabel ||
                  col.display_name ||
                  col.name ||
                  col.columnName ||
                  col.column_name,
              }));
              setModalSourceColumns(columns);
              console.log(`✅ [openModalWithData] 소스 테이블(${sourceTableName}) 컬럼 로드 완료:`, columns.length);
            }
          }
        } catch (error) {
          console.error("소스 테이블 컬럼 로드 실패:", error);
        }
      }

      // 타겟 화면의 테이블 컬럼 로드
      const targetScreenId = config.action?.targetScreenId;
      if (targetScreenId) {
        try {
          // 타겟 화면 정보 가져오기
          const screenResponse = await apiClient.get(`/screen-management/screens/${targetScreenId}`);
          console.log("[openModalWithData] 타겟 화면 응답:", screenResponse.data);

          if (screenResponse.data.success && screenResponse.data.data) {
            const targetTableName = screenResponse.data.data.tableName;
            console.log("[openModalWithData] 타겟 화면 테이블명:", targetTableName);

            if (targetTableName) {
              const columnResponse = await apiClient.get(`/table-management/tables/${targetTableName}/columns`);
              if (columnResponse.data.success) {
                let columnData = columnResponse.data.data;
                if (!Array.isArray(columnData) && columnData?.columns) columnData = columnData.columns;
                if (!Array.isArray(columnData) && columnData?.data) columnData = columnData.data;

                if (Array.isArray(columnData)) {
                  const columns = columnData.map((col: any) => ({
                    name: col.name || col.columnName || col.column_name,
                    label:
                      col.displayName ||
                      col.label ||
                      col.columnLabel ||
                      col.display_name ||
                      col.name ||
                      col.columnName ||
                      col.column_name,
                  }));
                  setModalTargetColumns(columns);
                  console.log(`✅ [openModalWithData] 타겟 테이블(${targetTableName}) 컬럼 로드 완료:`, columns.length);
                }
              }
            } else {
              console.warn("[openModalWithData] 타겟 화면에 테이블명이 없습니다.");
            }
          }
        } catch (error) {
          console.error("타겟 화면 테이블 컬럼 로드 실패:", error);
        }
      } else {
        console.warn("[openModalWithData] 타겟 화면 ID가 없습니다.");
      }
    };

    loadModalMappingColumns();
  }, [config.action?.type, config.action?.targetScreenId, allComponents, currentTableName]);

  // 화면 목록 가져오기 (현재 편집 중인 화면의 회사 코드 기준)
  useEffect(() => {
    const fetchScreens = async () => {
      try {
        setScreensLoading(true);
        // 현재 편집 중인 화면의 회사 코드 기준으로 화면 목록 조회
        const params: any = {
          page: 1,
          size: 9999, // 매우 큰 값으로 설정하여 전체 목록 가져오기
        };

        // 현재 화면의 회사 코드가 있으면 필터링 파라미터로 전달
        if (currentScreenCompanyCode) {
          params.companyCode = currentScreenCompanyCode;
        }

        const response = await apiClient.get("/screen-management/screens", {
          params,
        });

        if (response.data.success && Array.isArray(response.data.data)) {
          const screenList = response.data.data.map((screen: any) => ({
            id: screen.screenId,
            name: screen.screenName,
            description: screen.description,
          }));
          setScreens(screenList);
        }
      } catch (error) {
        // console.error("❌ 화면 목록 로딩 실패:", error);
      } finally {
        setScreensLoading(false);
      }
    };

    fetchScreens();
  }, [currentScreenCompanyCode]);

  // 결재 유형 목록 가져오기 (approval 액션일 때)
  useEffect(() => {
    if (localInputs.actionType !== "approval") return;
    const fetchApprovalDefinitions = async () => {
      setApprovalDefinitionsLoading(true);
      try {
        const res = await getApprovalDefinitions({ is_active: "Y" });
        if (res.success && res.data) {
          setApprovalDefinitions(res.data);
        }
      } catch {
        // 조용히 실패
      } finally {
        setApprovalDefinitionsLoading(false);
      }
    };
    fetchApprovalDefinitions();
  }, [localInputs.actionType]);

  // 테이블 컬럼 목록 가져오기 (테이블 이력 보기 액션일 때)
  useEffect(() => {
    const fetchTableColumns = async () => {
      // 테이블 이력 보기 액션이 아니면 스킵
      if (config.action?.type !== "view_table_history") {
        return;
      }

      // 1. 수동 입력된 테이블명 우선
      // 2. 없으면 현재 화면의 테이블명 사용
      const tableName = config.action?.historyTableName || currentTableName;

      // 테이블명이 없으면 스킵
      if (!tableName) {
        return;
      }

      try {
        setColumnsLoading(true);
        const response = await apiClient.get(`/table-management/tables/${tableName}/columns`, {
          params: {
            page: 1,
            size: 9999, // 전체 컬럼 가져오기
          },
        });

        // API 응답 구조: { success, data: { columns: [...], total, page, totalPages } }
        const columnData = response.data.data?.columns;

        if (!columnData || !Array.isArray(columnData)) {
          console.error("❌ 컬럼 데이터가 배열이 아닙니다:", columnData);
          setTableColumns([]);
          return;
        }

        if (response.data.success) {
          // ID 컬럼과 날짜 관련 컬럼 제외
          const filteredColumns = columnData
            .filter((col: any) => {
              const colName = col.columnName.toLowerCase();
              const dataType = col.dataType?.toLowerCase() || "";

              // ID 컬럼 제외 (id, _id로 끝나는 컬럼)
              if (colName === "id" || colName.endsWith("_id")) {
                return false;
              }

              // 날짜/시간 타입 제외 (데이터 타입 기준)
              if (dataType.includes("date") || dataType.includes("time") || dataType.includes("timestamp")) {
                return false;
              }

              // 날짜/시간 관련 컬럼명 제외 (컬럼명에 date, time, at 포함)
              if (
                colName.includes("date") ||
                colName.includes("time") ||
                colName.endsWith("_at") ||
                colName.startsWith("created") ||
                colName.startsWith("updated")
              ) {
                return false;
              }

              return true;
            })
            .map((col: any) => col.columnName);

          setTableColumns(filteredColumns);
        }
      } catch (error) {
        console.error("❌ 테이블 컬럼 로딩 실패:", error);
      } finally {
        setColumnsLoading(false);
      }
    };

    fetchTableColumns();
  }, [config.action?.type, config.action?.historyTableName, currentTableName]);

  // 검색 필터링 함수
  const filterScreens = (searchTerm: string) => {
    if (!searchTerm.trim()) return screens;
    return screens.filter(
      (screen) =>
        screen.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
        (screen.description && screen.description.toLowerCase().includes(searchTerm.toLowerCase())),
    );
  };

  return (
    <div className="space-y-4">
      {/* 모달 열기 액션 설정 */}
      {localInputs.actionType === "modal" && (
        <div className="bg-muted/50 mt-4 space-y-4 rounded-lg border p-4">
          <h4 className="text-foreground text-sm font-medium">모달 설정</h4>

          <div>
            <Label htmlFor="modal-title">모달 제목</Label>
            <Input
              id="modal-title"
              placeholder="모달 제목을 입력하세요"
              value={localInputs.modalTitle}
              onChange={(e) => {
                const newValue = e.target.value;
                setLocalInputs((prev) => ({ ...prev, modalTitle: newValue }));
                onUpdateProperty("componentConfig.action.modalTitle", newValue);
              }}
            />
          </div>

          <div>
            <Label htmlFor="modal-description">모달 설명</Label>
            <Input
              id="modal-description"
              placeholder="모달 설명을 입력하세요 (선택사항)"
              value={localInputs.modalDescription}
              onChange={(e) => {
                const newValue = e.target.value;
                setLocalInputs((prev) => ({ ...prev, modalDescription: newValue }));
                onUpdateProperty("componentConfig.action.modalDescription", newValue);
              }}
            />
            <p className="text-muted-foreground mt-1 text-xs">모달 제목 아래에 표시됩니다</p>
          </div>

          <div>
            <Label htmlFor="modal-size">모달 크기</Label>
            <Select
              value={component.componentConfig?.action?.modalSize || "md"}
              onValueChange={(value) => {
                onUpdateProperty("componentConfig.action.modalSize", value);
              }}
            >
              <SelectTrigger>
                <SelectValue placeholder="모달 크기 선택" />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="sm">작음 (Small)</SelectItem>
                <SelectItem value="md">보통 (Medium)</SelectItem>
                <SelectItem value="lg">큼 (Large)</SelectItem>
                <SelectItem value="xl">매우 큼 (Extra Large)</SelectItem>
              </SelectContent>
            </Select>
          </div>

          <div>
            <Label htmlFor="target-screen-modal">대상 화면 선택</Label>
            <Popover open={modalScreenOpen} onOpenChange={setModalScreenOpen}>
              <PopoverTrigger asChild>
                <Button
                  variant="outline"
                  role="combobox"
                  aria-expanded={modalScreenOpen}
                  className="h-6 w-full justify-between px-2 py-0 text-xs"
                  disabled={screensLoading}
                >
                  {config.action?.targetScreenId
                    ? screens.find((screen) => screen.id === parseInt(config.action?.targetScreenId))?.name ||
                      "화면을 선택하세요..."
                    : "화면을 선택하세요..."}
                  <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
                </Button>
              </PopoverTrigger>
              <PopoverContent className="p-0" align="start" style={{ width: "var(--radix-popover-trigger-width)" }}>
                <div className="flex flex-col">
                  <div className="flex items-center border-b px-3 py-2">
                    <Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
                    <Input
                      placeholder="화면 검색..."
                      value={modalSearchTerm}
                      onChange={(e) => setModalSearchTerm(e.target.value)}
                      className="border-0 p-0 focus-visible:ring-0"
                    />
                  </div>
                  <div className="max-h-[200px] overflow-auto">
                    {(() => {
                      const filteredScreens = filterScreens(modalSearchTerm);
                      if (screensLoading) {
                        return <div className="text-muted-foreground p-3 text-sm">화면 목록을 불러오는 중...</div>;
                      }
                      if (filteredScreens.length === 0) {
                        return <div className="text-muted-foreground p-3 text-sm">검색 결과가 없습니다.</div>;
                      }
                      return filteredScreens.map((screen, index) => (
                        <div
                          key={`modal-screen-${screen.id}-${index}`}
                          className="hover:bg-muted flex cursor-pointer items-center px-3 py-2"
                          onClick={() => {
                            onUpdateProperty("componentConfig.action.targetScreenId", screen.id);
                            setModalScreenOpen(false);
                            setModalSearchTerm("");
                          }}
                        >
                          <Check
                            className={cn(
                              "mr-2 h-4 w-4",
                              parseInt(config.action?.targetScreenId) === screen.id ? "opacity-100" : "opacity-0",
                            )}
                          />
                          <div className="flex flex-col">
                            <span className="font-medium">{screen.name}</span>
                            {screen.description && (
                              <span className="text-muted-foreground text-xs">{screen.description}</span>
                            )}
                          </div>
                        </div>
                      ));
                    })()}
                  </div>
                </div>
              </PopoverContent>
            </Popover>
          </div>

          {/* 선택된 데이터 전달 옵션 */}
          <div className="flex items-center space-x-2">
            <Checkbox
              id="auto-detect-data-source"
              checked={component.componentConfig?.action?.autoDetectDataSource === true}
              onCheckedChange={(checked) => {
                onUpdateProperty("componentConfig.action.autoDetectDataSource", checked);
                if (!checked) {
                  // 체크 해제 시 필드 매핑도 초기화
                  onUpdateProperty("componentConfig.action.fieldMappings", []);
                }
              }}
            />
            <div className="flex flex-col">
              <Label htmlFor="auto-detect-data-source" className="cursor-pointer text-sm">
                선택된 데이터 전달
              </Label>
              <p className="text-muted-foreground text-xs">
                TableList/SplitPanel에서 선택된 데이터를 모달에 자동으로 전달합니다
              </p>
            </div>
          </div>

          {/* 🆕 필드 매핑 UI (데이터 전달 활성화 + 테이블이 다른 경우) */}
          {component.componentConfig?.action?.autoDetectDataSource === true && (
            <div className="bg-background mt-4 space-y-3 rounded-lg border p-3">
              {/* 테이블 정보 표시 */}
              <div className="flex items-center justify-between text-xs">
                <div className="flex items-center gap-2">
                  <Database className="text-muted-foreground h-3 w-3" />
                  <span className="text-muted-foreground">소스:</span>
                  <span className="font-medium">{modalActionSourceTable || "감지 중..."}</span>
                </div>
                <span className="text-muted-foreground">→</span>
                <div className="flex items-center gap-2">
                  <span className="text-muted-foreground">대상:</span>
                  <span className="font-medium">{modalActionTargetTable || "감지 중..."}</span>
                </div>
              </div>

              {/* 테이블이 같으면 자동 매핑 안내 */}
              {modalActionSourceTable &&
                modalActionTargetTable &&
                modalActionSourceTable === modalActionTargetTable && (
                  <div className="rounded-md bg-emerald-50 p-2 text-xs text-emerald-700 dark:bg-emerald-950/30 dark:text-emerald-400">
                    동일한 테이블입니다. 컬럼명이 같은 필드는 자동으로 매핑됩니다.
                  </div>
                )}

              {/* 테이블이 다르면 필드 매핑 UI 표시 */}
              {modalActionSourceTable &&
                modalActionTargetTable &&
                modalActionSourceTable !== modalActionTargetTable && (
                  <div className="space-y-2">
                    <div className="flex items-center justify-between">
                      <Label className="text-xs font-medium">필드 매핑</Label>
                      <Button
                        type="button"
                        variant="outline"
                        size="sm"
                        className="h-6 text-xs"
                        onClick={() => {
                          const newMappings = [
                            ...(component.componentConfig?.action?.fieldMappings || []),
                            { sourceField: "", targetField: "" },
                          ];
                          setModalActionFieldMappings(newMappings);
                          onUpdateProperty("componentConfig.action.fieldMappings", newMappings);
                        }}
                      >
                        <Plus className="mr-1 h-3 w-3" />
                        매핑 추가
                      </Button>
                    </div>

                    {(component.componentConfig?.action?.fieldMappings || []).length === 0 && (
                      <p className="text-muted-foreground text-xs">
                        컬럼명이 다른 경우 매핑을 추가하세요. 매핑이 없으면 동일 컬럼명만 전달됩니다.
                      </p>
                    )}

                    {(component.componentConfig?.action?.fieldMappings || []).map((mapping: any, index: number) => (
                      <div key={index} className="flex items-center gap-2">
                        {/* 소스 필드 선택 */}
                        <Popover
                          open={modalFieldMappingSourceOpen[index] || false}
                          onOpenChange={(open) =>
                            setModalFieldMappingSourceOpen((prev) => ({ ...prev, [index]: open }))
                          }
                        >
                          <PopoverTrigger asChild>
                            <Button variant="outline" size="sm" className="h-7 flex-1 justify-between text-xs">
                              {mapping.sourceField
                                ? modalActionSourceColumns.find((c) => c.name === mapping.sourceField)?.label ||
                                  mapping.sourceField
                                : "소스 컬럼 선택"}
                              <ChevronsUpDown className="ml-1 h-3 w-3 opacity-50" />
                            </Button>
                          </PopoverTrigger>
                          <PopoverContent className="w-[200px] p-0" align="start">
                            <Command>
                              <CommandInput
                                placeholder="컬럼 검색..."
                                value={modalFieldMappingSourceSearch[index] || ""}
                                onValueChange={(val) =>
                                  setModalFieldMappingSourceSearch((prev) => ({ ...prev, [index]: val }))
                                }
                              />
                              <CommandList>
                                <CommandEmpty>컬럼을 찾을 수 없습니다.</CommandEmpty>
                                <CommandGroup>
                                  {modalActionSourceColumns
                                    .filter(
                                      (col) =>
                                        col.name
                                          .toLowerCase()
                                          .includes((modalFieldMappingSourceSearch[index] || "").toLowerCase()) ||
                                        col.label
                                          .toLowerCase()
                                          .includes((modalFieldMappingSourceSearch[index] || "").toLowerCase()),
                                    )
                                    .map((col) => (
                                      <CommandItem
                                        key={col.name}
                                        value={col.name}
                                        onSelect={() => {
                                          const newMappings = [
                                            ...(component.componentConfig?.action?.fieldMappings || []),
                                          ];
                                          newMappings[index] = { ...newMappings[index], sourceField: col.name };
                                          setModalActionFieldMappings(newMappings);
                                          onUpdateProperty("componentConfig.action.fieldMappings", newMappings);
                                          setModalFieldMappingSourceOpen((prev) => ({ ...prev, [index]: false }));
                                        }}
                                      >
                                        <Check
                                          className={cn(
                                            "mr-2 h-4 w-4",
                                            mapping.sourceField === col.name ? "opacity-100" : "opacity-0",
                                          )}
                                        />
                                        <div className="flex flex-col">
                                          <span className="text-xs font-medium">{col.label}</span>
                                          <span className="text-muted-foreground text-[10px]">{col.name}</span>
                                        </div>
                                      </CommandItem>
                                    ))}
                                </CommandGroup>
                              </CommandList>
                            </Command>
                          </PopoverContent>
                        </Popover>

                        <span className="text-muted-foreground text-xs">→</span>

                        {/* 대상 필드 선택 */}
                        <Popover
                          open={modalFieldMappingTargetOpen[index] || false}
                          onOpenChange={(open) =>
                            setModalFieldMappingTargetOpen((prev) => ({ ...prev, [index]: open }))
                          }
                        >
                          <PopoverTrigger asChild>
                            <Button variant="outline" size="sm" className="h-7 flex-1 justify-between text-xs">
                              {mapping.targetField
                                ? modalActionTargetColumns.find((c) => c.name === mapping.targetField)?.label ||
                                  mapping.targetField
                                : "대상 컬럼 선택"}
                              <ChevronsUpDown className="ml-1 h-3 w-3 opacity-50" />
                            </Button>
                          </PopoverTrigger>
                          <PopoverContent className="w-[200px] p-0" align="start">
                            <Command>
                              <CommandInput
                                placeholder="컬럼 검색..."
                                value={modalFieldMappingTargetSearch[index] || ""}
                                onValueChange={(val) =>
                                  setModalFieldMappingTargetSearch((prev) => ({ ...prev, [index]: val }))
                                }
                              />
                              <CommandList>
                                <CommandEmpty>컬럼을 찾을 수 없습니다.</CommandEmpty>
                                <CommandGroup>
                                  {modalActionTargetColumns
                                    .filter(
                                      (col) =>
                                        col.name
                                          .toLowerCase()
                                          .includes((modalFieldMappingTargetSearch[index] || "").toLowerCase()) ||
                                        col.label
                                          .toLowerCase()
                                          .includes((modalFieldMappingTargetSearch[index] || "").toLowerCase()),
                                    )
                                    .map((col) => (
                                      <CommandItem
                                        key={col.name}
                                        value={col.name}
                                        onSelect={() => {
                                          const newMappings = [
                                            ...(component.componentConfig?.action?.fieldMappings || []),
                                          ];
                                          newMappings[index] = { ...newMappings[index], targetField: col.name };
                                          setModalActionFieldMappings(newMappings);
                                          onUpdateProperty("componentConfig.action.fieldMappings", newMappings);
                                          setModalFieldMappingTargetOpen((prev) => ({ ...prev, [index]: false }));
                                        }}
                                      >
                                        <Check
                                          className={cn(
                                            "mr-2 h-4 w-4",
                                            mapping.targetField === col.name ? "opacity-100" : "opacity-0",
                                          )}
                                        />
                                        <div className="flex flex-col">
                                          <span className="text-xs font-medium">{col.label}</span>
                                          <span className="text-muted-foreground text-[10px]">{col.name}</span>
                                        </div>
                                      </CommandItem>
                                    ))}
                                </CommandGroup>
                              </CommandList>
                            </Command>
                          </PopoverContent>
                        </Popover>

                        {/* 삭제 버튼 */}
                        <Button
                          type="button"
                          variant="ghost"
                          size="sm"
                          className="text-destructive hover:bg-destructive/10 h-7 w-7 p-0"
                          onClick={() => {
                            const newMappings = (component.componentConfig?.action?.fieldMappings || []).filter(
                              (_: any, i: number) => i !== index,
                            );
                            setModalActionFieldMappings(newMappings);
                            onUpdateProperty("componentConfig.action.fieldMappings", newMappings);
                          }}
                        >
                          <X className="h-3 w-3" />
                        </Button>
                      </div>
                    ))}
                  </div>
                )}
            </div>
          )}
        </div>
      )}

      {/* 🆕 데이터 전달 + 모달 열기 액션 설정 (deprecated - 하위 호환성 유지) */}
      {component.componentConfig?.action?.type === "openModalWithData" && (
        <div className="mt-4 space-y-4 rounded-lg border bg-amber-50 p-4 dark:bg-amber-950/20">
          <h4 className="text-foreground text-sm font-medium">데이터 전달 + 모달 설정</h4>
          <p className="text-xs text-amber-600 dark:text-amber-400">
            이 옵션은 "모달 열기" 액션으로 통합되었습니다. 새 개발에서는 "모달 열기" + "선택된 데이터 전달"을
            사용하세요.
          </p>

          {/* 🆕 블록 기반 제목 빌더 */}
          <div className="space-y-2">
            <div className="flex items-center justify-between">
              <Label>모달 제목 구성</Label>
              <div className="flex gap-1">
                <Button type="button" variant="outline" size="sm" onClick={addTextBlock} className="h-6 text-xs">
                  <Type className="mr-1 h-3 w-3" />
                  텍스트 추가
                </Button>
                <Button type="button" variant="outline" size="sm" onClick={addFieldBlock} className="h-6 text-xs">
                  <Database className="mr-1 h-3 w-3" />
                  필드 추가
                </Button>
              </div>
            </div>

            {/* 블록 목록 */}
            <div className="space-y-2">
              {titleBlocks.length === 0 ? (
                <div className="text-muted-foreground rounded border-2 border-dashed py-4 text-center text-xs">
                  텍스트나 필드를 추가하여 제목을 구성하세요
                </div>
              ) : (
                titleBlocks.map((block, index) => (
                  <Card key={block.id} className="p-2">
                    <div className="flex items-start gap-2">
                      {/* 순서 변경 버튼 */}
                      <div className="flex flex-col gap-0.5">
                        <Button
                          type="button"
                          variant="ghost"
                          size="sm"
                          onClick={() => moveBlockUp(block.id)}
                          disabled={index === 0}
                          className="h-5 w-5 p-0"
                        >
                          <ChevronUp className="h-3 w-3" />
                        </Button>
                        <Button
                          type="button"
                          variant="ghost"
                          size="sm"
                          onClick={() => moveBlockDown(block.id)}
                          disabled={index === titleBlocks.length - 1}
                          className="h-5 w-5 p-0"
                        >
                          <ChevronDown className="h-3 w-3" />
                        </Button>
                      </div>

                      {/* 블록 타입 표시 */}
                      <div className="mt-1 flex-shrink-0">
                        {block.type === "text" ? (
                          <Type className="h-4 w-4 text-primary" />
                        ) : (
                          <Database className="h-4 w-4 text-emerald-500" />
                        )}
                      </div>

                      {/* 블록 설정 */}
                      <div className="flex-1 space-y-2">
                        {block.type === "text" ? (
                          // 텍스트 블록
                          <Input
                            placeholder="텍스트 입력 (예: 품목 상세정보 - )"
                            value={block.value}
                            onChange={(e) => updateBlock(block.id, { value: e.target.value })}
                            className="h-7 text-xs"
                          />
                        ) : (
                          // 필드 블록
                          <>
                            {/* 테이블 선택 - Combobox */}
                            <Popover
                              open={blockTablePopoverOpen[block.id] || false}
                              onOpenChange={(open) => {
                                setBlockTablePopoverOpen((prev) => ({ ...prev, [block.id]: open }));
                              }}
                            >
                              <PopoverTrigger asChild>
                                <Button
                                  variant="outline"
                                  role="combobox"
                                  className="h-7 w-full justify-between text-xs"
                                >
                                  {block.tableName
                                    ? availableTables.find((t) => t.name === block.tableName)?.label || block.tableName
                                    : "테이블 선택"}
                                  <ChevronsUpDown className="ml-2 h-3 w-3 shrink-0 opacity-50" />
                                </Button>
                              </PopoverTrigger>
                              <PopoverContent className="w-full p-0" align="start">
                                <Command shouldFilter={false}>
                                  <CommandInput
                                    placeholder="테이블 검색 (라벨 또는 이름)..."
                                    className="h-7 text-xs"
                                    value={blockTableSearches[block.id] || ""}
                                    onValueChange={(value) => {
                                      setBlockTableSearches((prev) => ({ ...prev, [block.id]: value }));
                                    }}
                                  />
                                  <CommandList>
                                    <CommandEmpty className="text-xs">테이블을 찾을 수 없습니다.</CommandEmpty>
                                    <CommandGroup>
                                      {availableTables
                                        .filter((table) => {
                                          const search = (blockTableSearches[block.id] || "").toLowerCase();
                                          if (!search) return true;
                                          return (
                                            table.label.toLowerCase().includes(search) ||
                                            table.name.toLowerCase().includes(search)
                                          );
                                        })
                                        .map((table) => (
                                          <CommandItem
                                            key={table.name}
                                            value={table.name}
                                            onSelect={() => {
                                              updateBlock(block.id, { tableName: table.name, value: "" });
                                              loadTableColumns(table.name);
                                              setBlockTableSearches((prev) => ({ ...prev, [block.id]: "" }));
                                              setBlockTablePopoverOpen((prev) => ({ ...prev, [block.id]: false }));
                                            }}
                                            className="text-xs"
                                          >
                                            <Check
                                              className={cn(
                                                "mr-2 h-3 w-3",
                                                block.tableName === table.name ? "opacity-100" : "opacity-0",
                                              )}
                                            />
                                            <span className="font-medium">{table.label}</span>
                                            <span className="text-muted-foreground ml-2 text-[10px]">
                                              ({table.name})
                                            </span>
                                          </CommandItem>
                                        ))}
                                    </CommandGroup>
                                  </CommandList>
                                </Command>
                              </PopoverContent>
                            </Popover>

                            {block.tableName && (
                              <>
                                {/* 컬럼 선택 - Combobox (라벨명 표시) */}
                                <Popover
                                  open={blockColumnPopoverOpen[block.id] || false}
                                  onOpenChange={(open) => {
                                    setBlockColumnPopoverOpen((prev) => ({ ...prev, [block.id]: open }));
                                  }}
                                >
                                  <PopoverTrigger asChild>
                                    <Button
                                      variant="outline"
                                      role="combobox"
                                      className="h-7 w-full justify-between text-xs"
                                    >
                                      {block.value
                                        ? tableColumnsMap[block.tableName]?.find((c) => c.name === block.value)
                                            ?.label || block.value
                                        : "컬럼 선택"}
                                      <ChevronsUpDown className="ml-2 h-3 w-3 shrink-0 opacity-50" />
                                    </Button>
                                  </PopoverTrigger>
                                  <PopoverContent className="w-full p-0" align="start">
                                    <Command shouldFilter={false}>
                                      <CommandInput
                                        placeholder="컬럼 검색 (라벨 또는 이름)..."
                                        className="h-7 text-xs"
                                        value={blockColumnSearches[block.id] || ""}
                                        onValueChange={(value) => {
                                          setBlockColumnSearches((prev) => ({ ...prev, [block.id]: value }));
                                        }}
                                      />
                                      <CommandList>
                                        <CommandEmpty className="text-xs">컬럼을 찾을 수 없습니다.</CommandEmpty>
                                        <CommandGroup>
                                          {(tableColumnsMap[block.tableName] || [])
                                            .filter((col) => {
                                              const search = (blockColumnSearches[block.id] || "").toLowerCase();
                                              if (!search) return true;
                                              return (
                                                col.label.toLowerCase().includes(search) ||
                                                col.name.toLowerCase().includes(search)
                                              );
                                            })
                                            .map((col) => (
                                              <CommandItem
                                                key={col.name}
                                                value={col.name}
                                                onSelect={() => {
                                                  updateBlock(block.id, {
                                                    value: col.name,
                                                    label: col.label,
                                                  });
                                                  setBlockColumnSearches((prev) => ({ ...prev, [block.id]: "" }));
                                                  setBlockColumnPopoverOpen((prev) => ({ ...prev, [block.id]: false }));
                                                }}
                                                className="text-xs"
                                              >
                                                <Check
                                                  className={cn(
                                                    "mr-2 h-3 w-3",
                                                    block.value === col.name ? "opacity-100" : "opacity-0",
                                                  )}
                                                />
                                                <span className="font-medium">{col.label}</span>
                                                <span className="text-muted-foreground ml-2 text-[10px]">
                                                  ({col.name})
                                                </span>
                                              </CommandItem>
                                            ))}
                                        </CommandGroup>
                                      </CommandList>
                                    </Command>
                                  </PopoverContent>
                                </Popover>

                                <Input
                                  placeholder="표시 라벨 (예: 품목명)"
                                  value={block.label || ""}
                                  onChange={(e) => updateBlock(block.id, { label: e.target.value })}
                                  className="h-7 text-xs"
                                />
                              </>
                            )}
                          </>
                        )}
                      </div>

                      {/* 삭제 버튼 */}
                      <Button
                        type="button"
                        variant="ghost"
                        size="sm"
                        onClick={() => removeBlock(block.id)}
                        className="h-7 w-7 p-0 text-destructive"
                      >
                        <X className="h-4 w-4" />
                      </Button>
                    </div>
                  </Card>
                ))
              )}
            </div>

            {/* 미리보기 */}
            {titleBlocks.length > 0 && (
              <div className="bg-muted mt-2 rounded p-2 text-xs">
                <span className="text-muted-foreground">미리보기: </span>
                <span className="font-medium">{generateTitlePreview()}</span>
              </div>
            )}

            <p className="text-muted-foreground text-[10px]">
              • 텍스트: 고정 텍스트 입력 (예: "품목 상세정보 - ")
              <br />
              • 필드: 이전 화면 데이터로 자동 채워짐 (예: 품목명, 규격)
              <br />
              • 순서 변경: ↑↓ 버튼으로 자유롭게 배치
              <br />• 데이터가 없으면 "표시 라벨"이 대신 표시됩니다
            </p>
          </div>

          <div>
            <Label htmlFor="modal-size-with-data">모달 크기</Label>
            <Select
              value={component.componentConfig?.action?.modalSize || "lg"}
              onValueChange={(value) => {
                onUpdateProperty("componentConfig.action.modalSize", value);
              }}
            >
              <SelectTrigger>
                <SelectValue placeholder="모달 크기 선택" />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="sm">작음 (Small)</SelectItem>
                <SelectItem value="md">보통 (Medium)</SelectItem>
                <SelectItem value="lg">큼 (Large) - 권장</SelectItem>
                <SelectItem value="xl">매우 큼 (Extra Large)</SelectItem>
              </SelectContent>
            </Select>
          </div>

          <div>
            <Label htmlFor="target-screen-with-data">대상 화면 선택</Label>
            <Popover open={modalScreenOpen} onOpenChange={setModalScreenOpen}>
              <PopoverTrigger asChild>
                <Button
                  variant="outline"
                  role="combobox"
                  aria-expanded={modalScreenOpen}
                  className="h-6 w-full justify-between px-2 py-0 text-xs"
                  disabled={screensLoading}
                >
                  {config.action?.targetScreenId
                    ? screens.find((screen) => screen.id === parseInt(config.action?.targetScreenId))?.name ||
                      "화면을 선택하세요..."
                    : "화면을 선택하세요..."}
                  <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
                </Button>
              </PopoverTrigger>
              <PopoverContent className="p-0" align="start" style={{ width: "var(--radix-popover-trigger-width)" }}>
                <div className="flex flex-col">
                  <div className="flex items-center border-b px-3 py-2">
                    <Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
                    <Input
                      placeholder="화면 검색..."
                      value={modalSearchTerm}
                      onChange={(e) => setModalSearchTerm(e.target.value)}
                      className="border-0 p-0 focus-visible:ring-0"
                    />
                  </div>
                  <div className="max-h-[200px] overflow-auto">
                    {(() => {
                      const filteredScreens = filterScreens(modalSearchTerm);
                      if (screensLoading) {
                        return <div className="text-muted-foreground p-3 text-sm">화면 목록을 불러오는 중...</div>;
                      }
                      if (filteredScreens.length === 0) {
                        return <div className="text-muted-foreground p-3 text-sm">검색 결과가 없습니다.</div>;
                      }
                      return filteredScreens.map((screen, index) => (
                        <div
                          key={`modal-data-screen-${screen.id}-${index}`}
                          className="hover:bg-muted flex cursor-pointer items-center px-3 py-2"
                          onClick={() => {
                            onUpdateProperty("componentConfig.action.targetScreenId", screen.id);
                            setModalScreenOpen(false);
                            setModalSearchTerm("");
                          }}
                        >
                          <Check
                            className={cn(
                              "mr-2 h-4 w-4",
                              parseInt(config.action?.targetScreenId) === screen.id ? "opacity-100" : "opacity-0",
                            )}
                          />
                          <div className="flex flex-col">
                            <span className="font-medium">{screen.name}</span>
                            {screen.description && (
                              <span className="text-muted-foreground text-xs">{screen.description}</span>
                            )}
                          </div>
                        </div>
                      ));
                    })()}
                  </div>
                </div>
              </PopoverContent>
            </Popover>
            <p className="text-muted-foreground mt-1 text-xs">
              SelectedItemsDetailInput 컴포넌트가 있는 화면을 선택하세요
            </p>
          </div>

          {/* 🆕 필드 매핑 설정 (소스 컬럼 → 타겟 컬럼) */}
          <div className="space-y-2 border-t pt-4">
            <div className="flex items-center justify-between">
              <Label className="text-xs font-medium">필드 매핑 (선택사항)</Label>
              <Button
                type="button"
                variant="outline"
                size="sm"
                className="h-6 text-[10px]"
                onClick={() => {
                  const currentMappings = config.action?.fieldMappings || [];
                  const newMapping = { sourceField: "", targetField: "" };
                  onUpdateProperty("componentConfig.action.fieldMappings", [...currentMappings, newMapping]);
                }}
              >
                <Plus className="mr-1 h-3 w-3" />
                매핑 추가
              </Button>
            </div>
            <p className="text-muted-foreground text-[10px]">
              소스 테이블의 컬럼명이 타겟 화면의 입력 필드 컬럼명과 다를 때 매핑을 설정하세요.
              <br />
              예: warehouse_code → warehouse_id (분할 패널의 창고코드를 모달의 창고ID에 매핑)
            </p>

            {/* 컬럼 로드 상태 표시 */}
            {modalSourceColumns.length > 0 || modalTargetColumns.length > 0 ? (
              <div className="text-muted-foreground bg-muted/50 rounded p-2 text-[10px]">
                소스 컬럼: {modalSourceColumns.length}개 / 타겟 컬럼: {modalTargetColumns.length}개
              </div>
            ) : (
              <div className="rounded bg-amber-50 p-2 text-[10px] text-amber-600 dark:bg-amber-950/20">
                분할 패널 또는 테이블 컴포넌트와 대상 화면을 설정하면 컬럼 목록이 로드됩니다.
              </div>
            )}

            {(config.action?.fieldMappings || []).length === 0 ? (
              <div className="rounded-md border border-dashed p-3 text-center">
                <p className="text-muted-foreground text-xs">매핑이 없으면 같은 이름의 컬럼끼리 자동으로 매핑됩니다.</p>
              </div>
            ) : (
              <div className="space-y-3">
                {(config.action?.fieldMappings || []).map((mapping: any, index: number) => (
                  <div key={index} className="bg-background space-y-2 rounded-md border p-3">
                    {/* 소스 필드 선택 (Combobox) - 세로 배치 */}
                    <div className="space-y-1">
                      <Label className="text-muted-foreground text-[10px]">소스 컬럼</Label>
                      <Popover
                        open={modalSourcePopoverOpen[index] || false}
                        onOpenChange={(open) => setModalSourcePopoverOpen((prev) => ({ ...prev, [index]: open }))}
                      >
                        <PopoverTrigger asChild>
                          <Button variant="outline" role="combobox" className="h-8 w-full justify-between text-xs">
                            <span className="truncate">
                              {mapping.sourceField
                                ? modalSourceColumns.find((c) => c.name === mapping.sourceField)?.label ||
                                  mapping.sourceField
                                : "소스 컬럼 선택"}
                            </span>
                            <ChevronsUpDown className="ml-1 h-3 w-3 shrink-0 opacity-50" />
                          </Button>
                        </PopoverTrigger>
                        <PopoverContent className="w-[--radix-popover-trigger-width] max-w-[280px] p-0" align="start">
                          <Command>
                            <CommandInput
                              placeholder="컬럼 검색..."
                              className="h-8 text-xs"
                              value={modalSourceSearch[index] || ""}
                              onValueChange={(value) => setModalSourceSearch((prev) => ({ ...prev, [index]: value }))}
                            />
                            <CommandList className="max-h-[200px]">
                              <CommandEmpty className="py-2 text-center text-xs">컬럼을 찾을 수 없습니다</CommandEmpty>
                              <CommandGroup>
                                {modalSourceColumns.map((col) => (
                                  <CommandItem
                                    key={col.name}
                                    value={`${col.label} ${col.name}`}
                                    onSelect={() => {
                                      const mappings = [...(config.action?.fieldMappings || [])];
                                      mappings[index] = { ...mappings[index], sourceField: col.name };
                                      onUpdateProperty("componentConfig.action.fieldMappings", mappings);
                                      setModalSourcePopoverOpen((prev) => ({ ...prev, [index]: false }));
                                    }}
                                    className="text-xs"
                                  >
                                    <Check
                                      className={cn(
                                        "mr-2 h-3 w-3",
                                        mapping.sourceField === col.name ? "opacity-100" : "opacity-0",
                                      )}
                                    />
                                    <span className="truncate">{col.label}</span>
                                    {col.label !== col.name && (
                                      <span className="text-muted-foreground ml-1 truncate">({col.name})</span>
                                    )}
                                  </CommandItem>
                                ))}
                              </CommandGroup>
                            </CommandList>
                          </Command>
                        </PopoverContent>
                      </Popover>
                    </div>

                    {/* 화살표 표시 */}
                    <div className="flex justify-center">
                      <span className="text-muted-foreground text-xs">↓</span>
                    </div>

                    {/* 타겟 필드 선택 (Combobox) - 세로 배치 */}
                    <div className="space-y-1">
                      <Label className="text-muted-foreground text-[10px]">타겟 컬럼</Label>
                      <Popover
                        open={modalTargetPopoverOpen[index] || false}
                        onOpenChange={(open) => setModalTargetPopoverOpen((prev) => ({ ...prev, [index]: open }))}
                      >
                        <PopoverTrigger asChild>
                          <Button variant="outline" role="combobox" className="h-8 w-full justify-between text-xs">
                            <span className="truncate">
                              {mapping.targetField
                                ? modalTargetColumns.find((c) => c.name === mapping.targetField)?.label ||
                                  mapping.targetField
                                : "타겟 컬럼 선택"}
                            </span>
                            <ChevronsUpDown className="ml-1 h-3 w-3 shrink-0 opacity-50" />
                          </Button>
                        </PopoverTrigger>
                        <PopoverContent className="w-[--radix-popover-trigger-width] max-w-[280px] p-0" align="start">
                          <Command>
                            <CommandInput
                              placeholder="컬럼 검색..."
                              className="h-8 text-xs"
                              value={modalTargetSearch[index] || ""}
                              onValueChange={(value) => setModalTargetSearch((prev) => ({ ...prev, [index]: value }))}
                            />
                            <CommandList className="max-h-[200px]">
                              <CommandEmpty className="py-2 text-center text-xs">컬럼을 찾을 수 없습니다</CommandEmpty>
                              <CommandGroup>
                                {modalTargetColumns.map((col) => (
                                  <CommandItem
                                    key={col.name}
                                    value={`${col.label} ${col.name}`}
                                    onSelect={() => {
                                      const mappings = [...(config.action?.fieldMappings || [])];
                                      mappings[index] = { ...mappings[index], targetField: col.name };
                                      onUpdateProperty("componentConfig.action.fieldMappings", mappings);
                                      setModalTargetPopoverOpen((prev) => ({ ...prev, [index]: false }));
                                    }}
                                    className="text-xs"
                                  >
                                    <Check
                                      className={cn(
                                        "mr-2 h-3 w-3",
                                        mapping.targetField === col.name ? "opacity-100" : "opacity-0",
                                      )}
                                    />
                                    <span className="truncate">{col.label}</span>
                                    {col.label !== col.name && (
                                      <span className="text-muted-foreground ml-1 truncate">({col.name})</span>
                                    )}
                                  </CommandItem>
                                ))}
                              </CommandGroup>
                            </CommandList>
                          </Command>
                        </PopoverContent>
                      </Popover>
                    </div>

                    {/* 삭제 버튼 */}
                    <div className="flex justify-end pt-1">
                      <Button
                        type="button"
                        variant="ghost"
                        size="sm"
                        className="text-destructive hover:bg-destructive/10 h-6 text-[10px]"
                        onClick={() => {
                          const mappings = [...(config.action?.fieldMappings || [])];
                          mappings.splice(index, 1);
                          onUpdateProperty("componentConfig.action.fieldMappings", mappings);
                        }}
                      >
                        <X className="mr-1 h-3 w-3" />
                        삭제
                      </Button>
                    </div>
                  </div>
                ))}
              </div>
            )}
          </div>
        </div>
      )}

      {/* 수정 액션 설정 */}
      {localInputs.actionType === "edit" && (
        <div className="bg-success/10 mt-4 space-y-4 rounded-lg border p-4">
          <h4 className="text-foreground text-sm font-medium">수정 설정</h4>

          <div>
            <Label htmlFor="edit-screen">수정 폼 화면 선택</Label>
            <Popover open={modalScreenOpen} onOpenChange={setModalScreenOpen}>
              <PopoverTrigger asChild>
                <Button
                  variant="outline"
                  role="combobox"
                  aria-expanded={modalScreenOpen}
                  className="h-6 w-full justify-between px-2 py-0 text-xs"
                  disabled={screensLoading}
                >
                  {config.action?.targetScreenId
                    ? screens.find((screen) => screen.id === parseInt(config.action?.targetScreenId))?.name ||
                      "수정 폼 화면을 선택하세요..."
                    : "수정 폼 화면을 선택하세요..."}
                  <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
                </Button>
              </PopoverTrigger>
              <PopoverContent className="p-0" align="start" style={{ width: "var(--radix-popover-trigger-width)" }}>
                <div className="flex flex-col">
                  <div className="flex items-center border-b px-3 py-2">
                    <Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
                    <Input
                      placeholder="화면 검색..."
                      value={modalSearchTerm}
                      onChange={(e) => setModalSearchTerm(e.target.value)}
                      className="border-0 p-0 focus-visible:ring-0"
                    />
                  </div>
                  <div className="max-h-[200px] overflow-auto">
                    {(() => {
                      const filteredScreens = filterScreens(modalSearchTerm);
                      if (screensLoading) {
                        return <div className="text-muted-foreground p-3 text-sm">화면 목록을 불러오는 중...</div>;
                      }
                      if (filteredScreens.length === 0) {
                        return <div className="text-muted-foreground p-3 text-sm">검색 결과가 없습니다.</div>;
                      }
                      return filteredScreens.map((screen, index) => (
                        <div
                          key={`edit-screen-${screen.id}-${index}`}
                          className="hover:bg-muted flex cursor-pointer items-center px-3 py-2"
                          onClick={() => {
                            onUpdateProperty("componentConfig.action.targetScreenId", screen.id);
                            setModalScreenOpen(false);
                            setModalSearchTerm("");
                          }}
                        >
                          <Check
                            className={cn(
                              "mr-2 h-4 w-4",
                              parseInt(config.action?.targetScreenId) === screen.id ? "opacity-100" : "opacity-0",
                            )}
                          />
                          <div className="flex flex-col">
                            <span className="font-medium">{screen.name}</span>
                            {screen.description && (
                              <span className="text-muted-foreground text-xs">{screen.description}</span>
                            )}
                          </div>
                        </div>
                      ));
                    })()}
                  </div>
                </div>
              </PopoverContent>
            </Popover>
            <p className="text-muted-foreground mt-1 text-xs">
              선택된 데이터가 이 폼 화면에 자동으로 로드되어 수정할 수 있습니다
            </p>
          </div>

          <div>
            <Label htmlFor="edit-mode">수정 모드</Label>
            <Select
              value={component.componentConfig?.action?.editMode || "modal"}
              onValueChange={(value) => {
                onUpdateProperty("componentConfig.action.editMode", value);
              }}
            >
              <SelectTrigger>
                <SelectValue placeholder="수정 모드 선택" />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="modal">모달로 열기</SelectItem>
                <SelectItem value="navigate">새 페이지로 이동</SelectItem>
                <SelectItem value="inline">현재 화면에서 수정</SelectItem>
              </SelectContent>
            </Select>
          </div>

          {(component.componentConfig?.action?.editMode || "modal") === "modal" && (
            <>
              <div>
                <Label htmlFor="edit-modal-title">모달 제목</Label>
                <Input
                  id="edit-modal-title"
                  placeholder="모달 제목을 입력하세요 (예: 데이터 수정)"
                  value={localInputs.editModalTitle}
                  onChange={(e) => {
                    const newValue = e.target.value;
                    setLocalInputs((prev) => ({ ...prev, editModalTitle: newValue }));
                    onUpdateProperty("componentConfig.action.editModalTitle", newValue);
                    onUpdateProperty("webTypeConfig.editModalTitle", newValue);
                  }}
                />
                <p className="text-muted-foreground mt-1 text-xs">비워두면 기본 제목이 표시됩니다</p>
              </div>

              <div>
                <Label htmlFor="edit-modal-description">모달 설명</Label>
                <Input
                  id="edit-modal-description"
                  placeholder="모달 설명을 입력하세요 (예: 선택한 데이터를 수정합니다)"
                  value={localInputs.editModalDescription}
                  onChange={(e) => {
                    const newValue = e.target.value;
                    setLocalInputs((prev) => ({ ...prev, editModalDescription: newValue }));
                    onUpdateProperty("componentConfig.action.editModalDescription", newValue);
                    onUpdateProperty("webTypeConfig.editModalDescription", newValue);
                  }}
                />
                <p className="text-muted-foreground mt-1 text-xs">비워두면 설명이 표시되지 않습니다</p>
              </div>

              <div>
                <Label htmlFor="edit-modal-size">모달 크기</Label>
                <Select
                  value={component.componentConfig?.action?.modalSize || "md"}
                  onValueChange={(value) => {
                    onUpdateProperty("componentConfig.action.modalSize", value);
                  }}
                >
                  <SelectTrigger>
                    <SelectValue placeholder="모달 크기 선택" />
                  </SelectTrigger>
                  <SelectContent>
                    <SelectItem value="sm">작음 (Small)</SelectItem>
                    <SelectItem value="md">보통 (Medium)</SelectItem>
                    <SelectItem value="lg">큼 (Large)</SelectItem>
                    <SelectItem value="xl">매우 큼 (Extra Large)</SelectItem>
                    <SelectItem value="full">전체 화면 (Full)</SelectItem>
                  </SelectContent>
                </Select>
              </div>
            </>
          )}

          <div>
            <Label htmlFor="edit-group-by-column">그룹화 컬럼</Label>
            <Popover open={groupByColumnOpen} onOpenChange={setGroupByColumnOpen}>
              <PopoverTrigger asChild>
                <Button
                  variant="outline"
                  role="combobox"
                  aria-expanded={groupByColumnOpen}
                  className="h-8 w-full justify-between text-xs"
                >
                  {localInputs.groupByColumn ? (
                    <span>
                      {localInputs.groupByColumn}
                      {currentTableColumns.find((col) => col.name === localInputs.groupByColumn)?.label &&
                        currentTableColumns.find((col) => col.name === localInputs.groupByColumn)?.label !==
                          localInputs.groupByColumn && (
                          <span className="text-muted-foreground ml-1">
                            ({currentTableColumns.find((col) => col.name === localInputs.groupByColumn)?.label})
                          </span>
                        )}
                    </span>
                  ) : (
                    <span className="text-muted-foreground">컬럼을 선택하세요</span>
                  )}
                  <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
                </Button>
              </PopoverTrigger>
              <PopoverContent className="p-0" align="start" style={{ width: "var(--radix-popover-trigger-width)" }}>
                <div className="flex flex-col">
                  <div className="flex items-center border-b px-3 py-2">
                    <Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
                    <Input
                      placeholder="컬럼명 또는 라벨 검색..."
                      value={groupByColumnSearch}
                      onChange={(e) => setGroupByColumnSearch(e.target.value)}
                      className="border-0 p-0 focus-visible:ring-0"
                    />
                  </div>
                  <div className="max-h-[200px] overflow-auto">
                    {currentTableColumns.length === 0 ? (
                      <div className="text-muted-foreground p-3 text-sm">
                        {currentTableName ? "컬럼을 불러오는 중..." : "테이블이 설정되지 않았습니다"}
                      </div>
                    ) : (
                      <>
                        {/* 선택 해제 옵션 */}
                        <div
                          className="hover:bg-muted flex cursor-pointer items-center px-3 py-2"
                          onClick={() => {
                            setLocalInputs((prev) => ({ ...prev, groupByColumn: "" }));
                            onUpdateProperty("componentConfig.action.groupByColumns", undefined);
                            setGroupByColumnOpen(false);
                            setGroupByColumnSearch("");
                          }}
                        >
                          <Check
                            className={cn("mr-2 h-4 w-4", !localInputs.groupByColumn ? "opacity-100" : "opacity-0")}
                          />
                          <span className="text-muted-foreground">선택 안 함</span>
                        </div>
                        {/* 컬럼 목록 */}
                        {currentTableColumns
                          .filter((col) => {
                            if (!groupByColumnSearch) return true;
                            const search = groupByColumnSearch.toLowerCase();
                            return col.name.toLowerCase().includes(search) || col.label.toLowerCase().includes(search);
                          })
                          .map((col) => (
                            <div
                              key={col.name}
                              className="hover:bg-muted flex cursor-pointer items-center px-3 py-2"
                              onClick={() => {
                                setLocalInputs((prev) => ({ ...prev, groupByColumn: col.name }));
                                onUpdateProperty("componentConfig.action.groupByColumns", [col.name]);
                                setGroupByColumnOpen(false);
                                setGroupByColumnSearch("");
                              }}
                            >
                              <Check
                                className={cn(
                                  "mr-2 h-4 w-4",
                                  localInputs.groupByColumn === col.name ? "opacity-100" : "opacity-0",
                                )}
                              />
                              <div className="flex flex-col">
                                <span className="font-medium">{col.name}</span>
                                {col.label !== col.name && (
                                  <span className="text-muted-foreground text-xs">{col.label}</span>
                                )}
                              </div>
                            </div>
                          ))}
                      </>
                    )}
                  </div>
                </div>
              </PopoverContent>
            </Popover>
            <p className="text-muted-foreground mt-1 text-xs">여러 행을 하나의 그룹으로 묶어서 수정할 때 사용합니다</p>
          </div>
        </div>
      )}

      {/* 복사 액션 설정 */}
      {localInputs.actionType === "copy" && (
        <div className="mt-4 space-y-4 rounded-lg border bg-primary/10 p-4">
          <h4 className="text-foreground text-sm font-medium">복사 설정 (품목코드 자동 초기화)</h4>

          <div>
            <Label htmlFor="copy-screen">복사 폼 화면 선택</Label>
            <Popover open={modalScreenOpen} onOpenChange={setModalScreenOpen}>
              <PopoverTrigger asChild>
                <Button
                  variant="outline"
                  role="combobox"
                  aria-expanded={modalScreenOpen}
                  className="h-6 w-full justify-between px-2 py-0 text-xs"
                  disabled={screensLoading}
                >
                  {config.action?.targetScreenId
                    ? screens.find((screen) => screen.id === parseInt(config.action?.targetScreenId))?.name ||
                      "복사 폼 화면을 선택하세요..."
                    : "복사 폼 화면을 선택하세요..."}
                  <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
                </Button>
              </PopoverTrigger>
              <PopoverContent className="p-0" align="start" style={{ width: "var(--radix-popover-trigger-width)" }}>
                <div className="flex flex-col">
                  <div className="flex items-center border-b px-3 py-2">
                    <Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
                    <Input
                      placeholder="화면 검색..."
                      value={modalSearchTerm}
                      onChange={(e) => setModalSearchTerm(e.target.value)}
                      className="border-0 p-0 focus-visible:ring-0"
                    />
                  </div>
                  <div className="max-h-[200px] overflow-auto">
                    {(() => {
                      const filteredScreens = filterScreens(modalSearchTerm);
                      if (screensLoading) {
                        return <div className="text-muted-foreground p-3 text-sm">화면 목록을 불러오는 중...</div>;
                      }
                      if (filteredScreens.length === 0) {
                        return <div className="text-muted-foreground p-3 text-sm">검색 결과가 없습니다.</div>;
                      }
                      return filteredScreens.map((screen, index) => (
                        <div
                          key={`copy-screen-${screen.id}-${index}`}
                          className="hover:bg-muted flex cursor-pointer items-center px-3 py-2"
                          onClick={() => {
                            onUpdateProperty("componentConfig.action.targetScreenId", screen.id);
                            setModalScreenOpen(false);
                            setModalSearchTerm("");
                          }}
                        >
                          <Check
                            className={cn(
                              "mr-2 h-4 w-4",
                              parseInt(config.action?.targetScreenId) === screen.id ? "opacity-100" : "opacity-0",
                            )}
                          />
                          <div className="flex flex-col">
                            <span className="font-medium">{screen.name}</span>
                            {screen.description && (
                              <span className="text-muted-foreground text-xs">{screen.description}</span>
                            )}
                          </div>
                        </div>
                      ));
                    })()}
                  </div>
                </div>
              </PopoverContent>
            </Popover>
            <p className="text-muted-foreground mt-1 text-xs">
              선택된 데이터가 복사되며, 품목코드는 자동으로 초기화됩니다
            </p>
          </div>

          <div>
            <Label htmlFor="copy-mode">복사 모드</Label>
            <Select
              value={component.componentConfig?.action?.editMode || "modal"}
              onValueChange={(value) => {
                onUpdateProperty("componentConfig.action.editMode", value);
              }}
            >
              <SelectTrigger>
                <SelectValue placeholder="복사 모드 선택" />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="modal">모달로 열기</SelectItem>
                <SelectItem value="navigate">새 페이지로 이동</SelectItem>
              </SelectContent>
            </Select>
          </div>

          {(component.componentConfig?.action?.editMode || "modal") === "modal" && (
            <>
              <div>
                <Label htmlFor="copy-modal-title">모달 제목</Label>
                <Input
                  id="copy-modal-title"
                  placeholder="모달 제목을 입력하세요 (예: 데이터 복사)"
                  value={localInputs.editModalTitle}
                  onChange={(e) => {
                    const newValue = e.target.value;
                    setLocalInputs((prev) => ({ ...prev, editModalTitle: newValue }));
                    onUpdateProperty("componentConfig.action.editModalTitle", newValue);
                    onUpdateProperty("webTypeConfig.editModalTitle", newValue);
                  }}
                />
                <p className="text-muted-foreground mt-1 text-xs">비워두면 기본 제목이 표시됩니다</p>
              </div>

              <div>
                <Label htmlFor="copy-modal-description">모달 설명</Label>
                <Input
                  id="copy-modal-description"
                  placeholder="모달 설명을 입력하세요 (예: 선택한 데이터를 복사합니다)"
                  value={localInputs.editModalDescription}
                  onChange={(e) => {
                    const newValue = e.target.value;
                    setLocalInputs((prev) => ({ ...prev, editModalDescription: newValue }));
                    onUpdateProperty("componentConfig.action.editModalDescription", newValue);
                    onUpdateProperty("webTypeConfig.editModalDescription", newValue);
                  }}
                />
                <p className="text-muted-foreground mt-1 text-xs">비워두면 설명이 표시되지 않습니다</p>
              </div>

              <div>
                <Label htmlFor="copy-modal-size">모달 크기</Label>
                <Select
                  value={component.componentConfig?.action?.modalSize || "md"}
                  onValueChange={(value) => {
                    onUpdateProperty("componentConfig.action.modalSize", value);
                  }}
                >
                  <SelectTrigger>
                    <SelectValue placeholder="모달 크기 선택" />
                  </SelectTrigger>
                  <SelectContent>
                    <SelectItem value="sm">작음 (Small)</SelectItem>
                    <SelectItem value="md">보통 (Medium)</SelectItem>
                    <SelectItem value="lg">큼 (Large)</SelectItem>
                    <SelectItem value="xl">매우 큼 (Extra Large)</SelectItem>
                    <SelectItem value="full">전체 화면 (Full)</SelectItem>
                  </SelectContent>
                </Select>
              </div>
            </>
          )}
        </div>
      )}

      {/* 테이블 이력 보기 액션 설정 */}
      {localInputs.actionType === "view_table_history" && (
        <div className="mt-4 space-y-4">
          <div>
            <Label>
              전체 이력 표시 컬럼 (필수) <span className="text-destructive">*</span>
            </Label>

            <Popover open={displayColumnOpen} onOpenChange={setDisplayColumnOpen}>
              <PopoverTrigger asChild>
                <Button
                  variant="outline"
                  role="combobox"
                  aria-expanded={displayColumnOpen}
                  className="mt-2 h-8 w-full justify-between text-xs"
                  disabled={columnsLoading || tableColumns.length === 0}
                >
                  {columnsLoading
                    ? "로딩 중..."
                    : config.action?.historyDisplayColumn
                      ? config.action.historyDisplayColumn
                      : tableColumns.length === 0
                        ? "사용 가능한 컬럼이 없습니다"
                        : "컬럼을 선택하세요"}
                  <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
                </Button>
              </PopoverTrigger>
              <PopoverContent className="p-0" style={{ width: "var(--radix-popover-trigger-width)" }} align="start">
                <Command>
                  <CommandInput placeholder="컬럼 검색..." className="text-xs" />
                  <CommandList>
                    <CommandEmpty className="text-xs">컬럼을 찾을 수 없습니다.</CommandEmpty>
                    <CommandGroup>
                      {tableColumns.map((column) => (
                        <CommandItem
                          key={column}
                          value={column}
                          onSelect={(currentValue) => {
                            onUpdateProperty("componentConfig.action.historyDisplayColumn", currentValue);
                            setDisplayColumnOpen(false);
                          }}
                          className="text-xs"
                        >
                          <Check
                            className={cn(
                              "mr-2 h-4 w-4",
                              config.action?.historyDisplayColumn === column ? "opacity-100" : "opacity-0",
                            )}
                          />
                          {column}
                        </CommandItem>
                      ))}
                    </CommandGroup>
                  </CommandList>
                </Command>
              </PopoverContent>
            </Popover>
          </div>
        </div>
      )}

      {/* 페이지 이동 액션 설정 */}
      {localInputs.actionType === "navigate" && (
        <div className="bg-muted/50 mt-4 space-y-4 rounded-lg border p-4">
          <h4 className="text-foreground text-sm font-medium">페이지 이동 설정</h4>

          <div>
            <Label htmlFor="target-screen-nav">이동할 화면 선택</Label>
            <Popover open={navScreenOpen} onOpenChange={setNavScreenOpen}>
              <PopoverTrigger asChild>
                <Button
                  variant="outline"
                  role="combobox"
                  aria-expanded={navScreenOpen}
                  className="h-6 w-full justify-between px-2 py-0 text-xs"
                  disabled={screensLoading}
                >
                  {config.action?.targetScreenId
                    ? screens.find((screen) => screen.id === parseInt(config.action?.targetScreenId))?.name ||
                      "화면을 선택하세요..."
                    : "화면을 선택하세요..."}
                  <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
                </Button>
              </PopoverTrigger>
              <PopoverContent className="p-0" align="start" style={{ width: "var(--radix-popover-trigger-width)" }}>
                <div className="flex flex-col">
                  <div className="flex items-center border-b px-3 py-2">
                    <Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
                    <Input
                      placeholder="화면 검색..."
                      value={navSearchTerm}
                      onChange={(e) => setNavSearchTerm(e.target.value)}
                      className="border-0 p-0 focus-visible:ring-0"
                    />
                  </div>
                  <div className="max-h-[200px] overflow-auto">
                    {(() => {
                      const filteredScreens = filterScreens(navSearchTerm);
                      if (screensLoading) {
                        return <div className="text-muted-foreground p-3 text-sm">화면 목록을 불러오는 중...</div>;
                      }
                      if (filteredScreens.length === 0) {
                        return <div className="text-muted-foreground p-3 text-sm">검색 결과가 없습니다.</div>;
                      }
                      return filteredScreens.map((screen, index) => (
                        <div
                          key={`navigate-screen-${screen.id}-${index}`}
                          className="hover:bg-muted flex cursor-pointer items-center px-3 py-2"
                          onClick={() => {
                            onUpdateProperty("componentConfig.action.targetScreenId", screen.id);
                            setNavScreenOpen(false);
                            setNavSearchTerm("");
                          }}
                        >
                          <Check
                            className={cn(
                              "mr-2 h-4 w-4",
                              parseInt(config.action?.targetScreenId) === screen.id ? "opacity-100" : "opacity-0",
                            )}
                          />
                          <div className="flex flex-col">
                            <span className="font-medium">{screen.name}</span>
                            {screen.description && (
                              <span className="text-muted-foreground text-xs">{screen.description}</span>
                            )}
                          </div>
                        </div>
                      ));
                    })()}
                  </div>
                </div>
              </PopoverContent>
            </Popover>
            <p className="text-muted-foreground mt-1 text-xs">
              선택한 화면으로 /screens/{"{"}화면ID{"}"} 형태로 이동합니다
            </p>
          </div>

          <div>
            <Label htmlFor="target-url">또는 직접 URL 입력 (고급)</Label>
            <Input
              id="target-url"
              placeholder="예: /admin/users 또는 https://example.com"
              value={localInputs.targetUrl}
              onChange={(e) => {
                const newValue = e.target.value;
                setLocalInputs((prev) => ({ ...prev, targetUrl: newValue }));
                onUpdateProperty("componentConfig.action.targetUrl", newValue);
              }}
              className="h-6 w-full px-2 py-0 text-xs"
            />
            <p className="text-muted-foreground mt-1 text-xs">URL을 입력하면 화면 선택보다 우선 적용됩니다</p>
          </div>
        </div>
      )}

      {/* 엑셀 다운로드 액션 설정 */}
      {localInputs.actionType === "excel_download" && (
        <div className="bg-muted/50 mt-4 space-y-4 rounded-lg border p-4">
          <h4 className="text-foreground text-sm font-medium">엑셀 다운로드 설정</h4>

          <div>
            <Label htmlFor="excel-filename">파일명 (선택사항)</Label>
            <Input
              id="excel-filename"
              placeholder="예: 데이터목록 (기본값: export)"
              value={config.action?.excelFileName || ""}
              onChange={(e) => onUpdateProperty("componentConfig.action.excelFileName", e.target.value)}
              className="h-8 text-xs"
            />
            <p className="text-muted-foreground mt-1 text-xs">확장자(.xlsx)는 자동으로 추가됩니다</p>
          </div>

          <div>
            <Label htmlFor="excel-sheetname">시트명 (선택사항)</Label>
            <Input
              id="excel-sheetname"
              placeholder="예: Sheet1 (기본값)"
              value={config.action?.excelSheetName || ""}
              onChange={(e) => onUpdateProperty("componentConfig.action.excelSheetName", e.target.value)}
              className="h-8 text-xs"
            />
          </div>

          <div className="flex items-center justify-between">
            <Label htmlFor="excel-include-headers">헤더 포함</Label>
            <Switch
              id="excel-include-headers"
              checked={config.action?.excelIncludeHeaders !== false}
              onCheckedChange={(checked) => onUpdateProperty("componentConfig.action.excelIncludeHeaders", checked)}
            />
          </div>
        </div>
      )}

      {/* 엑셀 업로드 액션 설정 */}
      {localInputs.actionType === "excel_upload" && (
        <ExcelUploadConfigSection
          config={config}
          onUpdateProperty={onUpdateProperty}
          allComponents={allComponents}
          currentTableName={currentTableName}
        />
      )}

      {/* 다중 테이블 엑셀 업로드: 설정 불필요 (버튼 클릭 시 화면 테이블에서 자동 감지) */}

      {/* 바코드 스캔 액션 설정 */}
      {localInputs.actionType === "barcode_scan" && (
        <div className="bg-muted/50 mt-4 space-y-4 rounded-lg border p-4">
          <h4 className="text-foreground text-sm font-medium">📷 바코드 스캔 설정</h4>

          <div>
            <Label htmlFor="barcode-target-field">
              대상 필드명 <span className="text-destructive">*</span>
            </Label>
            <Input
              id="barcode-target-field"
              placeholder="예: barcode, qr_code"
              value={config.action?.barcodeTargetField || ""}
              onChange={(e) => onUpdateProperty("componentConfig.action.barcodeTargetField", e.target.value)}
              className="h-8 text-xs"
            />
            <p className="text-muted-foreground mt-1 text-xs">스캔 결과가 입력될 폼 필드명</p>
          </div>

          <div>
            <Label htmlFor="barcode-format">바코드 형식</Label>
            <Select
              value={config.action?.barcodeFormat || "all"}
              onValueChange={(value) => onUpdateProperty("componentConfig.action.barcodeFormat", value)}
            >
              <SelectTrigger className="h-8 text-xs">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="all">모든 형식</SelectItem>
                <SelectItem value="1d">1D 바코드만 (CODE128, EAN13 등)</SelectItem>
                <SelectItem value="2d">2D 바코드만 (QR코드, DataMatrix 등)</SelectItem>
              </SelectContent>
            </Select>
          </div>

          <div className="flex items-center justify-between">
            <Label htmlFor="barcode-auto-submit">스캔 후 자동 저장</Label>
            <Switch
              id="barcode-auto-submit"
              checked={config.action?.barcodeAutoSubmit === true}
              onCheckedChange={(checked) => onUpdateProperty("componentConfig.action.barcodeAutoSubmit", checked)}
            />
          </div>
        </div>
      )}

      {/* 코드 병합 액션 설정 */}
      {localInputs.actionType === "code_merge" && (
        <div className="bg-muted/50 mt-4 space-y-4 rounded-lg border p-4">
          <h4 className="text-foreground text-sm font-medium">🔀 코드 병합 설정</h4>

          <div>
            <Label htmlFor="merge-column-name">
              병합할 컬럼명 <span className="text-destructive">*</span>
            </Label>
            <Input
              id="merge-column-name"
              placeholder="예: item_code, product_id"
              value={config.action?.mergeColumnName || ""}
              onChange={(e) => onUpdateProperty("componentConfig.action.mergeColumnName", e.target.value)}
              className="h-8 text-xs"
            />
            <p className="text-muted-foreground mt-1 text-xs">
              병합할 컬럼명 (예: item_code). 이 컬럼이 있는 모든 테이블에 병합이 적용됩니다.
            </p>
          </div>

          <div className="flex items-center justify-between">
            <div className="space-y-0.5">
              <Label htmlFor="merge-show-preview">병합 전 미리보기</Label>
              <p className="text-muted-foreground text-xs">영향받을 테이블과 행 수를 미리 확인합니다</p>
            </div>
            <Switch
              id="merge-show-preview"
              checked={config.action?.mergeShowPreview !== false}
              onCheckedChange={(checked) => onUpdateProperty("componentConfig.action.mergeShowPreview", checked)}
            />
          </div>

          <div className="rounded-md bg-primary/10 p-3 dark:bg-primary/15">
            <p className="text-xs text-primary dark:text-primary/60">
              <strong>사용 방법:</strong>
              <br />
              1. 테이블에서 병합할 두 개의 행을 선택합니다
              <br />
              2. 이 버튼을 클릭하면 병합 방향을 선택할 수 있습니다
              <br />
              3. 데이터는 삭제되지 않고, 컬럼 값만 변경됩니다
            </p>
          </div>
        </div>
      )}

      {/* 공차등록 설정 - 운행알림으로 통합되어 주석 처리 */}
      {/* {localInputs.actionType === "empty_vehicle" && (
        <div className="mt-4 space-y-4 rounded-lg border bg-muted/50 p-4">
          ... 공차등록 설정 UI 생략 ...
        </div>
      )} */}

      {/* 운행알림 및 종료 설정 */}
      {localInputs.actionType === "operation_control" && (
        <div className="bg-muted/50 mt-4 space-y-4 rounded-lg border p-4">
          <h4 className="text-foreground text-sm font-medium">🚗 운행알림 및 종료 설정</h4>

          <div>
            <Label htmlFor="update-table">
              대상 테이블 <span className="text-destructive">*</span>
            </Label>
            <Select
              value={config.action?.updateTableName || currentTableName || ""}
              onValueChange={(value) => {
                onUpdateProperty("componentConfig.action.updateTableName", value);
                onUpdateProperty("componentConfig.action.updateTargetField", "");
              }}
            >
              <SelectTrigger className="h-8 text-xs">
                <SelectValue placeholder="테이블 선택" />
              </SelectTrigger>
              <SelectContent>
                {availableTables.map((table) => (
                  <SelectItem key={table.name} value={table.name} className="text-xs">
                    {table.label || table.name}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
            <p className="text-muted-foreground mt-1 text-xs">필드 값을 변경할 테이블 (기본: 현재 화면 테이블)</p>
          </div>

          <div className="grid grid-cols-2 gap-4">
            <div>
              <Label htmlFor="update-target-field">
                변경할 필드명 <span className="text-destructive">*</span>
              </Label>
              <Input
                id="update-target-field"
                placeholder="예: status"
                value={config.action?.updateTargetField || ""}
                onChange={(e) => onUpdateProperty("componentConfig.action.updateTargetField", e.target.value)}
                className="h-8 text-xs"
              />
              <p className="text-muted-foreground mt-1 text-xs">변경할 DB 컬럼</p>
            </div>
            <div>
              <Label htmlFor="update-target-value">
                변경할 값 <span className="text-destructive">*</span>
              </Label>
              <Input
                id="update-target-value"
                placeholder="예: active"
                value={config.action?.updateTargetValue || ""}
                onChange={(e) => onUpdateProperty("componentConfig.action.updateTargetValue", e.target.value)}
                className="h-8 text-xs"
              />
              <p className="text-muted-foreground mt-1 text-xs">변경할 값 (문자열, 숫자)</p>
            </div>
          </div>

          {/* 🆕 키 필드 설정 (레코드 식별용) */}
          <div className="mt-4 border-t pt-4">
            <h5 className="text-muted-foreground mb-3 text-xs font-medium">레코드 식별 설정</h5>
            <div className="grid grid-cols-2 gap-4">
              <div>
                <Label htmlFor="update-key-field">
                  키 필드 (DB 컬럼) <span className="text-destructive">*</span>
                </Label>
                <Input
                  id="update-key-field"
                  placeholder="예: user_id"
                  value={config.action?.updateKeyField || ""}
                  onChange={(e) => onUpdateProperty("componentConfig.action.updateKeyField", e.target.value)}
                  className="h-8 text-xs"
                />
                <p className="text-muted-foreground mt-1 text-xs">레코드를 찾을 DB 컬럼명</p>
              </div>
              <div>
                <Label htmlFor="update-key-source">
                  키 값 소스 <span className="text-destructive">*</span>
                </Label>
                <Select
                  value={config.action?.updateKeySourceField || ""}
                  onValueChange={(value) => onUpdateProperty("componentConfig.action.updateKeySourceField", value)}
                >
                  <SelectTrigger className="h-8 text-xs">
                    <SelectValue placeholder="키 값 소스 선택" />
                  </SelectTrigger>
                  <SelectContent>
                    <SelectItem value="__userId__" className="text-xs">
                      <span className="flex items-center gap-1">
                        <span className="text-amber-500">🔑</span> 로그인 사용자 ID
                      </span>
                    </SelectItem>
                    <SelectItem value="__userName__" className="text-xs">
                      <span className="flex items-center gap-1">
                        <span className="text-amber-500">🔑</span> 로그인 사용자 이름
                      </span>
                    </SelectItem>
                    <SelectItem value="__companyCode__" className="text-xs">
                      <span className="flex items-center gap-1">
                        <span className="text-amber-500">🔑</span> 회사 코드
                      </span>
                    </SelectItem>
                    {tableColumns.map((column) => (
                      <SelectItem key={column} value={column} className="text-xs">
                        {column}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
                <p className="text-muted-foreground mt-1 text-xs">키 값을 가져올 소스</p>
              </div>
            </div>
          </div>

          <div className="flex items-center justify-between">
            <div className="space-y-0.5">
              <Label htmlFor="update-auto-save">변경 후 자동 저장</Label>
              <p className="text-muted-foreground text-xs">버튼 클릭 시 즉시 DB에 저장</p>
            </div>
            <Switch
              id="update-auto-save"
              checked={config.action?.updateAutoSave !== false}
              onCheckedChange={(checked) => onUpdateProperty("componentConfig.action.updateAutoSave", checked)}
            />
          </div>

          <div>
            <Label htmlFor="update-confirm-message">확인 메시지 (선택)</Label>
            <Input
              id="update-confirm-message"
              placeholder="예: 운행을 시작하시겠습니까?"
              value={config.action?.confirmMessage || ""}
              onChange={(e) => onUpdateProperty("componentConfig.action.confirmMessage", e.target.value)}
              className="h-8 text-xs"
            />
            <p className="text-muted-foreground mt-1 text-xs">입력하면 변경 전 확인 창이 표시됩니다</p>
          </div>

          <div className="grid grid-cols-2 gap-4">
            <div>
              <Label htmlFor="update-success-message">성공 메시지 (선택)</Label>
              <Input
                id="update-success-message"
                placeholder="예: 운행이 시작되었습니다."
                value={config.action?.successMessage || ""}
                onChange={(e) => onUpdateProperty("componentConfig.action.successMessage", e.target.value)}
                className="h-8 text-xs"
              />
            </div>
            <div>
              <Label htmlFor="update-error-message">오류 메시지 (선택)</Label>
              <Input
                id="update-error-message"
                placeholder="예: 운행 시작에 실패했습니다."
                value={config.action?.errorMessage || ""}
                onChange={(e) => onUpdateProperty("componentConfig.action.errorMessage", e.target.value)}
                className="h-8 text-xs"
              />
            </div>
          </div>

          {/* 위치정보 수집 옵션 */}
          <div className="mt-4 border-t pt-4">
            <div className="flex items-center justify-between">
              <div className="space-y-0.5">
                <Label htmlFor="update-with-geolocation">위치정보도 함께 수집</Label>
                <p className="text-muted-foreground text-xs">상태 변경과 함께 현재 GPS 좌표를 수집합니다</p>
              </div>
              <Switch
                id="update-with-geolocation"
                checked={config.action?.updateWithGeolocation === true}
                onCheckedChange={(checked) => onUpdateProperty("componentConfig.action.updateWithGeolocation", checked)}
              />
            </div>

            {config.action?.updateWithGeolocation && (
              <div className="mt-3 space-y-3 rounded-md bg-amber-50 p-3 dark:bg-amber-950">
                <div className="grid grid-cols-2 gap-2">
                  <div>
                    <Label>
                      위도 저장 필드 <span className="text-destructive">*</span>
                    </Label>
                    <Input
                      placeholder="예: latitude"
                      value={config.action?.updateGeolocationLatField || ""}
                      onChange={(e) =>
                        onUpdateProperty("componentConfig.action.updateGeolocationLatField", e.target.value)
                      }
                      className="h-8 text-xs"
                    />
                  </div>
                  <div>
                    <Label>
                      경도 저장 필드 <span className="text-destructive">*</span>
                    </Label>
                    <Input
                      placeholder="예: longitude"
                      value={config.action?.updateGeolocationLngField || ""}
                      onChange={(e) =>
                        onUpdateProperty("componentConfig.action.updateGeolocationLngField", e.target.value)
                      }
                      className="h-8 text-xs"
                    />
                  </div>
                </div>
                <div className="grid grid-cols-2 gap-2">
                  <div>
                    <Label>정확도 필드 (선택)</Label>
                    <Input
                      placeholder="예: accuracy"
                      value={config.action?.updateGeolocationAccuracyField || ""}
                      onChange={(e) =>
                        onUpdateProperty("componentConfig.action.updateGeolocationAccuracyField", e.target.value)
                      }
                      className="h-8 text-xs"
                    />
                  </div>
                  <div>
                    <Label>타임스탬프 필드 (선택)</Label>
                    <Input
                      placeholder="예: location_time"
                      value={config.action?.updateGeolocationTimestampField || ""}
                      onChange={(e) =>
                        onUpdateProperty("componentConfig.action.updateGeolocationTimestampField", e.target.value)
                      }
                      className="h-8 text-xs"
                    />
                  </div>
                </div>
                <p className="text-[10px] text-amber-700 dark:text-amber-300">
                  버튼 클릭 시 GPS 위치를 수집하여 위 필드에 저장합니다.
                </p>
              </div>
            )}
          </div>

          {/* 🆕 연속 위치 추적 설정 */}
          <div className="flex items-center justify-between">
            <div>
              <Label htmlFor="update-with-tracking">연속 위치 추적</Label>
              <p className="text-muted-foreground text-xs">10초마다 위치를 경로 테이블에 저장합니다</p>
            </div>
            <Switch
              id="update-with-tracking"
              checked={config.action?.updateWithTracking === true}
              onCheckedChange={(checked) => onUpdateProperty("componentConfig.action.updateWithTracking", checked)}
            />
          </div>

          {config.action?.updateWithTracking && (
            <div className="mt-3 space-y-3 rounded-md bg-emerald-50 p-3 dark:bg-emerald-950">
              <div>
                <Label>
                  추적 모드 <span className="text-destructive">*</span>
                </Label>
                <Select
                  value={config.action?.updateTrackingMode || "start"}
                  onValueChange={(value) => onUpdateProperty("componentConfig.action.updateTrackingMode", value)}
                >
                  <SelectTrigger className="h-8 text-xs">
                    <SelectValue placeholder="모드 선택" />
                  </SelectTrigger>
                  <SelectContent>
                    <SelectItem value="start">추적 시작 (운행 시작)</SelectItem>
                    <SelectItem value="stop">추적 종료 (운행 종료)</SelectItem>
                  </SelectContent>
                </Select>
              </div>

              {config.action?.updateTrackingMode === "start" && (
                <div>
                  <Label>위치 저장 주기 (초)</Label>
                  <Input
                    type="number"
                    placeholder="10"
                    value={(config.action?.updateTrackingInterval || 10000) / 1000}
                    onChange={(e) =>
                      onUpdateProperty(
                        "componentConfig.action.updateTrackingInterval",
                        parseInt(e.target.value) * 1000 || 10000,
                      )
                    }
                    className="h-8 text-xs"
                    min={5}
                    max={300}
                  />
                  <p className="text-muted-foreground mt-1 text-[10px]">5초 ~ 300초 사이로 설정 (기본: 10초)</p>
                </div>
              )}

              <p className="text-[10px] text-emerald-700 dark:text-emerald-300">
                {config.action?.updateTrackingMode === "start"
                  ? "버튼 클릭 시 연속 위치 추적이 시작되고, vehicle_location_history 테이블에 경로가 저장됩니다."
                  : "버튼 클릭 시 진행 중인 위치 추적이 종료됩니다."}
              </p>
            </div>
          )}

          {/* 🆕 버튼 활성화 조건 설정 */}
          <div className="mt-4 border-t pt-4">
            <h5 className="text-muted-foreground mb-3 text-xs font-medium">버튼 활성화 조건</h5>

            {/* 출발지/도착지 필수 체크 */}
            <div className="flex items-center justify-between">
              <div>
                <Label htmlFor="require-location">출발지/도착지 필수</Label>
                <p className="text-muted-foreground text-xs">선택하지 않으면 버튼 비활성화</p>
              </div>
              <Switch
                id="require-location"
                checked={config.action?.requireLocationFields === true}
                onCheckedChange={(checked) => onUpdateProperty("componentConfig.action.requireLocationFields", checked)}
              />
            </div>

            {config.action?.requireLocationFields && (
              <div className="mt-3 space-y-2 rounded-md bg-amber-50 p-3 dark:bg-orange-950">
                <div className="grid grid-cols-2 gap-2">
                  <div>
                    <Label>출발지 필드명</Label>
                    <Input
                      placeholder="departure"
                      value={config.action?.trackingDepartureField || "departure"}
                      onChange={(e) =>
                        onUpdateProperty("componentConfig.action.trackingDepartureField", e.target.value)
                      }
                      className="h-8 text-xs"
                    />
                  </div>
                  <div>
                    <Label>도착지 필드명</Label>
                    <Input
                      placeholder="destination"
                      value={config.action?.trackingArrivalField || "destination"}
                      onChange={(e) => onUpdateProperty("componentConfig.action.trackingArrivalField", e.target.value)}
                      className="h-8 text-xs"
                    />
                  </div>
                </div>
              </div>
            )}

            {/* 상태 기반 활성화 조건 */}
            <div className="mt-4 flex items-center justify-between">
              <div>
                <Label htmlFor="enable-on-status">상태 기반 활성화</Label>
                <p className="text-muted-foreground text-xs">특정 상태일 때만 버튼 활성화</p>
              </div>
              <Switch
                id="enable-on-status"
                checked={config.action?.enableOnStatusCheck === true}
                onCheckedChange={(checked) => onUpdateProperty("componentConfig.action.enableOnStatusCheck", checked)}
              />
            </div>

            {config.action?.enableOnStatusCheck && (
              <div className="mt-3 space-y-2 rounded-md bg-purple-50 p-3 dark:bg-purple-950">
                <div>
                  <Label>상태 조회 테이블</Label>
                  <Select
                    value={config.action?.statusCheckTableName || "vehicles"}
                    onValueChange={(value) => onUpdateProperty("componentConfig.action.statusCheckTableName", value)}
                  >
                    <SelectTrigger className="h-8 text-xs">
                      <SelectValue />
                    </SelectTrigger>
                    <SelectContent>
                      {availableTables.map((table) => (
                        <SelectItem key={table.name} value={table.name} className="text-xs">
                          {table.label || table.name}
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                  <p className="text-muted-foreground mt-1 text-[10px]">상태를 조회할 테이블 (기본: vehicles)</p>
                </div>
                <div>
                  <Label>조회 키 필드</Label>
                  <Input
                    placeholder="user_id"
                    value={config.action?.statusCheckKeyField || "user_id"}
                    onChange={(e) => onUpdateProperty("componentConfig.action.statusCheckKeyField", e.target.value)}
                    className="h-8 text-xs"
                  />
                  <p className="text-muted-foreground mt-1 text-[10px]">
                    현재 로그인 사용자 ID로 조회할 필드 (기본: user_id)
                  </p>
                </div>
                <div>
                  <Label>상태 컬럼명</Label>
                  <Input
                    placeholder="status"
                    value={config.action?.statusCheckField || "status"}
                    onChange={(e) => onUpdateProperty("componentConfig.action.statusCheckField", e.target.value)}
                    className="h-8 text-xs"
                  />
                  <p className="text-muted-foreground mt-1 text-[10px]">상태 값이 저장된 컬럼명 (기본: status)</p>
                </div>
                <div>
                  <Label>상태 조건</Label>
                  <Select
                    value={config.action?.statusConditionType || "enableOn"}
                    onValueChange={(value) => onUpdateProperty("componentConfig.action.statusConditionType", value)}
                  >
                    <SelectTrigger className="h-8 text-xs">
                      <SelectValue />
                    </SelectTrigger>
                    <SelectContent>
                      <SelectItem value="enableOn">이 상태일 때만 활성화</SelectItem>
                      <SelectItem value="disableOn">이 상태일 때 비활성화</SelectItem>
                    </SelectContent>
                  </Select>
                </div>
                <div>
                  <Label>상태값 (쉼표로 구분)</Label>
                  <Input
                    placeholder="예: active, inactive"
                    value={config.action?.statusConditionValues || ""}
                    onChange={(e) => onUpdateProperty("componentConfig.action.statusConditionValues", e.target.value)}
                    className="h-8 text-xs"
                  />
                  <p className="text-muted-foreground mt-1 text-[10px]">여러 상태값은 쉼표(,)로 구분</p>
                </div>
              </div>
            )}
          </div>

          <div className="rounded-md bg-primary/10 p-3 dark:bg-primary/15">
            <p className="text-xs text-primary dark:text-primary/60">
              <strong>사용 예시:</strong>
              <br />
              - 운행 시작: status를 &quot;active&quot;로 + 연속 추적 시작
              <br />
              - 운행 종료: status를 &quot;completed&quot;로 + 연속 추적 종료
              <br />- 공차등록: status를 &quot;inactive&quot;로 + 1회성 위치정보 수집
            </p>
          </div>
        </div>
      )}

      {/* 데이터 전달 액션 설정 */}
      {localInputs.actionType === "transferData" && (
        <div className="bg-muted/50 mt-4 space-y-4 rounded-lg border p-4">
          <h4 className="text-foreground text-sm font-medium">📦 데이터 전달 설정</h4>

          {/* 소스 컴포넌트 선택 (Combobox) */}
          <div>
            <Label>
              소스 컴포넌트 <span className="text-destructive">*</span>
            </Label>
            <Select
              value={config.action?.dataTransfer?.sourceComponentId || ""}
              onValueChange={(value) =>
                onUpdateProperty("componentConfig.action.dataTransfer.sourceComponentId", value)
              }
            >
              <SelectTrigger className="h-8 text-xs">
                <SelectValue placeholder="데이터를 가져올 컴포넌트 선택" />
              </SelectTrigger>
              <SelectContent>
                {/* 자동 탐색 옵션 (레이어별 테이블이 다를 때 유용) */}
                <SelectItem value="__auto__">
                  <div className="flex items-center gap-2">
                    <span className="text-xs font-medium">자동 탐색 (현재 활성 테이블)</span>
                    <span className="text-muted-foreground text-[10px]">(auto)</span>
                  </div>
                </SelectItem>
                {/* 데이터 제공 가능한 컴포넌트 필터링 (모든 레이어 포함) */}
                {allComponents
                  .filter((comp: any) => {
                    const type = comp.componentType || comp.type || "";
                    return ["table-list", "repeater-field-group", "form-group", "data-table"].some((t) =>
                      type.includes(t),
                    );
                  })
                  .map((comp: any) => {
                    const compType = comp.componentType || comp.type || "unknown";
                    const compLabel = comp.label || comp.componentConfig?.title || comp.id;
                    const layerName = comp._layerName;
                    return (
                      <SelectItem key={comp.id} value={comp.id}>
                        <div className="flex items-center gap-2">
                          <span className="text-xs font-medium">{compLabel}</span>
                          <span className="text-muted-foreground text-[10px]">({compType})</span>
                          {layerName && (
                            <span className="rounded bg-amber-100 px-1 text-[9px] text-amber-700 dark:bg-amber-900/30 dark:text-amber-400">
                              {layerName}
                            </span>
                          )}
                        </div>
                      </SelectItem>
                    );
                  })}
                {allComponents.filter((comp: any) => {
                  const type = comp.componentType || comp.type || "";
                  return ["table-list", "repeater-field-group", "form-group", "data-table"].some((t) =>
                    type.includes(t),
                  );
                }).length === 0 && (
                  <SelectItem value="__none__" disabled>
                    데이터 제공 가능한 컴포넌트가 없습니다
                  </SelectItem>
                )}
              </SelectContent>
            </Select>
            <p className="text-muted-foreground mt-1 text-xs">
              레이어별로 다른 테이블이 있을 경우 "자동 탐색"을 선택하면 현재 활성화된 레이어의 테이블을 자동으로
              사용합니다
            </p>
          </div>

          <div>
            <Label htmlFor="target-type">
              타겟 타입 <span className="text-destructive">*</span>
            </Label>
            <Select
              value={config.action?.dataTransfer?.targetType || "component"}
              onValueChange={(value) => onUpdateProperty("componentConfig.action.dataTransfer.targetType", value)}
            >
              <SelectTrigger className="h-8 text-xs">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="component">같은 화면의 컴포넌트</SelectItem>
                <SelectItem value="splitPanel">분할 패널 반대편 화면</SelectItem>
                <SelectItem value="screen" disabled>
                  다른 화면 (구현 예정)
                </SelectItem>
              </SelectContent>
            </Select>
            {config.action?.dataTransfer?.targetType === "splitPanel" && (
              <p className="text-muted-foreground mt-1 text-[10px]">
                이 버튼이 분할 패널 내부에 있어야 합니다. 좌측 화면에서 우측으로, 또는 우측에서 좌측으로 데이터가
                전달됩니다.
              </p>
            )}
          </div>

          {/* 타겟 컴포넌트 선택 (같은 화면의 컴포넌트일 때만) */}
          {config.action?.dataTransfer?.targetType === "component" && (
            <div>
              <Label>
                타겟 컴포넌트 <span className="text-destructive">*</span>
              </Label>
              <Select
                value={config.action?.dataTransfer?.targetComponentId || ""}
                onValueChange={(value) => {
                  onUpdateProperty("componentConfig.action.dataTransfer.targetComponentId", value);
                  // 선택한 컴포넌트가 다른 레이어에 있으면 targetLayerId도 저장
                  const selectedComp = allComponents.find((c: any) => c.id === value);
                  if (selectedComp && (selectedComp as any)._layerId) {
                    onUpdateProperty(
                      "componentConfig.action.dataTransfer.targetLayerId",
                      (selectedComp as any)._layerId,
                    );
                  } else {
                    onUpdateProperty("componentConfig.action.dataTransfer.targetLayerId", undefined);
                  }
                }}
              >
                <SelectTrigger className="h-8 text-xs">
                  <SelectValue placeholder="데이터를 받을 컴포넌트 선택" />
                </SelectTrigger>
                <SelectContent>
                  {/* 데이터 수신 가능한 컴포넌트 필터링 (모든 레이어 포함, 소스와 다른 컴포넌트만) */}
                  {allComponents
                    .filter((comp: any) => {
                      const type = comp.componentType || comp.type || "";
                      const isReceivable = ["table-list", "repeater-field-group", "form-group", "data-table"].some(
                        (t) => type.includes(t),
                      );
                      return isReceivable && comp.id !== config.action?.dataTransfer?.sourceComponentId;
                    })
                    .map((comp: any) => {
                      const compType = comp.componentType || comp.type || "unknown";
                      const compLabel = comp.label || comp.componentConfig?.title || comp.id;
                      const layerName = comp._layerName;
                      return (
                        <SelectItem key={comp.id} value={comp.id}>
                          <div className="flex items-center gap-2">
                            <span className="text-xs font-medium">{compLabel}</span>
                            <span className="text-muted-foreground text-[10px]">({compType})</span>
                            {layerName && (
                              <span className="rounded bg-amber-100 px-1 text-[9px] text-amber-700 dark:bg-amber-900/30 dark:text-amber-400">
                                {layerName}
                              </span>
                            )}
                          </div>
                        </SelectItem>
                      );
                    })}
                  {allComponents.filter((comp: any) => {
                    const type = comp.componentType || comp.type || "";
                    const isReceivable = ["table-list", "repeater-field-group", "form-group", "data-table"].some((t) =>
                      type.includes(t),
                    );
                    return isReceivable && comp.id !== config.action?.dataTransfer?.sourceComponentId;
                  }).length === 0 && (
                    <SelectItem value="__none__" disabled>
                      데이터 수신 가능한 컴포넌트가 없습니다
                    </SelectItem>
                  )}
                </SelectContent>
              </Select>
              <p className="text-muted-foreground mt-1 text-xs">테이블, 반복 필드 그룹 등 데이터를 받는 컴포넌트</p>
            </div>
          )}

          {/* 분할 패널 반대편 타겟 설정 */}
          {config.action?.dataTransfer?.targetType === "splitPanel" && (
            <div>
              <Label>타겟 컴포넌트 ID (선택사항)</Label>
              <Input
                value={config.action?.dataTransfer?.targetComponentId || ""}
                onChange={(e) =>
                  onUpdateProperty("componentConfig.action.dataTransfer.targetComponentId", e.target.value)
                }
                placeholder="비워두면 첫 번째 수신 가능 컴포넌트로 전달"
                className="h-8 text-xs"
              />
              <p className="text-muted-foreground mt-1 text-xs">
                반대편 화면의 특정 컴포넌트 ID를 지정하거나, 비워두면 자동으로 첫 번째 수신 가능 컴포넌트로 전달됩니다.
              </p>
            </div>
          )}

          <div>
            <Label htmlFor="transfer-mode">데이터 전달 모드</Label>
            <Select
              value={config.action?.dataTransfer?.mode || "append"}
              onValueChange={(value) => onUpdateProperty("componentConfig.action.dataTransfer.mode", value)}
            >
              <SelectTrigger className="h-8 text-xs">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="append">추가 (Append)</SelectItem>
                <SelectItem value="replace">교체 (Replace)</SelectItem>
                <SelectItem value="merge">병합 (Merge)</SelectItem>
              </SelectContent>
            </Select>
            <p className="text-muted-foreground mt-1 text-xs">기존 데이터를 어떻게 처리할지 선택</p>
          </div>

          <div className="flex items-center justify-between">
            <div className="space-y-0.5">
              <Label htmlFor="clear-after-transfer">전달 후 소스 선택 초기화</Label>
              <p className="text-muted-foreground text-xs">데이터 전달 후 소스의 선택을 해제합니다</p>
            </div>
            <Switch
              id="clear-after-transfer"
              checked={config.action?.dataTransfer?.clearAfterTransfer === true}
              onCheckedChange={(checked) =>
                onUpdateProperty("componentConfig.action.dataTransfer.clearAfterTransfer", checked)
              }
            />
          </div>

          <div className="flex items-center justify-between">
            <div className="space-y-0.5">
              <Label htmlFor="confirm-before-transfer">전달 전 확인 메시지</Label>
              <p className="text-muted-foreground text-xs">데이터 전달 전 확인 다이얼로그를 표시합니다</p>
            </div>
            <Switch
              id="confirm-before-transfer"
              checked={config.action?.dataTransfer?.confirmBeforeTransfer === true}
              onCheckedChange={(checked) =>
                onUpdateProperty("componentConfig.action.dataTransfer.confirmBeforeTransfer", checked)
              }
            />
          </div>

          {config.action?.dataTransfer?.confirmBeforeTransfer && (
            <div>
              <Label htmlFor="confirm-message">확인 메시지</Label>
              <Input
                id="confirm-message"
                placeholder="선택한 항목을 전달하시겠습니까?"
                value={config.action?.dataTransfer?.confirmMessage || ""}
                onChange={(e) => onUpdateProperty("componentConfig.action.dataTransfer.confirmMessage", e.target.value)}
                className="h-8 text-xs"
              />
            </div>
          )}

          <div className="space-y-2">
            <Label>검증 설정</Label>
            <div className="space-y-2 rounded-md border p-3">
              <div className="flex items-center gap-2">
                <Label htmlFor="min-selection" className="text-xs">
                  최소 선택 개수
                </Label>
                <Input
                  id="min-selection"
                  type="number"
                  placeholder="0"
                  value={config.action?.dataTransfer?.validation?.minSelection || ""}
                  onChange={(e) =>
                    onUpdateProperty(
                      "componentConfig.action.dataTransfer.validation.minSelection",
                      parseInt(e.target.value) || 0,
                    )
                  }
                  className="h-8 w-20 text-xs"
                />
              </div>
              <div className="flex items-center gap-2">
                <Label htmlFor="max-selection" className="text-xs">
                  최대 선택 개수
                </Label>
                <Input
                  id="max-selection"
                  type="number"
                  placeholder="제한없음"
                  value={config.action?.dataTransfer?.validation?.maxSelection || ""}
                  onChange={(e) =>
                    onUpdateProperty(
                      "componentConfig.action.dataTransfer.validation.maxSelection",
                      parseInt(e.target.value) || undefined,
                    )
                  }
                  className="h-8 w-20 text-xs"
                />
              </div>
            </div>
          </div>

          <div className="space-y-2">
            <Label>추가 데이터 소스 (선택사항)</Label>
            <p className="text-muted-foreground text-xs">
              조건부 컨테이너의 카테고리 값 등 추가 데이터를 함께 전달할 수 있습니다
            </p>
            <div className="space-y-2 rounded-md border p-3">
              <div>
                <Label className="text-xs">추가 컴포넌트</Label>
                <Select
                  value={config.action?.dataTransfer?.additionalSources?.[0]?.componentId || ""}
                  onValueChange={(value) => {
                    const currentSources = config.action?.dataTransfer?.additionalSources || [];
                    const newSources = [...currentSources];
                    if (newSources.length === 0) {
                      newSources.push({ componentId: value, fieldName: "" });
                    } else {
                      newSources[0] = { ...newSources[0], componentId: value };
                    }
                    onUpdateProperty("componentConfig.action.dataTransfer.additionalSources", newSources);
                  }}
                >
                  <SelectTrigger className="h-8 text-xs">
                    <SelectValue placeholder="추가 데이터 컴포넌트 선택 (선택사항)" />
                  </SelectTrigger>
                  <SelectContent>
                    <SelectItem value="__clear__">
                      <span className="text-muted-foreground">선택 안 함</span>
                    </SelectItem>
                    {/* 추가 데이터 제공 가능한 컴포넌트 (조건부 컨테이너, 셀렉트박스 등) */}
                    {allComponents
                      .filter((comp: any) => {
                        const type = comp.componentType || comp.type || "";
                        // 소스/타겟과 다른 컴포넌트 중 값을 제공할 수 있는 타입
                        return ["conditional-container", "select-basic", "select", "combobox"].some((t) =>
                          type.includes(t),
                        );
                      })
                      .map((comp: any) => {
                        const compType = comp.componentType || comp.type || "unknown";
                        const compLabel = comp.label || comp.componentConfig?.controlLabel || comp.id;
                        return (
                          <SelectItem key={comp.id} value={comp.id}>
                            <div className="flex items-center gap-2">
                              <span className="text-xs font-medium">{compLabel}</span>
                              <span className="text-muted-foreground text-[10px]">({compType})</span>
                            </div>
                          </SelectItem>
                        );
                      })}
                  </SelectContent>
                </Select>
                <p className="text-muted-foreground mt-1 text-xs">
                  조건부 컨테이너, 셀렉트박스 등 (카테고리 값 전달용)
                </p>
              </div>
              <div>
                <Label htmlFor="additional-field-name" className="text-xs">
                  타겟 필드명 (선택사항)
                </Label>
                <Popover>
                  <PopoverTrigger asChild>
                    <Button variant="outline" role="combobox" className="h-8 w-full justify-between text-xs">
                      {(() => {
                        const fieldName = config.action?.dataTransfer?.additionalSources?.[0]?.fieldName;
                        if (!fieldName) return "필드 선택 (비워두면 전체 데이터)";
                        const cols = mappingTargetColumns.length > 0 ? mappingTargetColumns : currentTableColumns;
                        const found = cols.find((c) => c.name === fieldName);
                        return found ? `${found.label || found.name}` : fieldName;
                      })()}
                      <ChevronsUpDown className="ml-2 h-3 w-3 shrink-0 opacity-50" />
                    </Button>
                  </PopoverTrigger>
                  <PopoverContent className="w-[240px] p-0" align="start">
                    <Command>
                      <CommandInput placeholder="컬럼 검색..." className="h-8 text-xs" />
                      <CommandList>
                        <CommandEmpty className="py-2 text-center text-xs">컬럼을 찾을 수 없습니다.</CommandEmpty>
                        <CommandGroup>
                          <CommandItem
                            value="__none__"
                            onSelect={() => {
                              const currentSources = config.action?.dataTransfer?.additionalSources || [];
                              const newSources = [...currentSources];
                              if (newSources.length === 0) {
                                newSources.push({ componentId: "", fieldName: "" });
                              } else {
                                newSources[0] = { ...newSources[0], fieldName: "" };
                              }
                              onUpdateProperty("componentConfig.action.dataTransfer.additionalSources", newSources);
                            }}
                            className="text-xs"
                          >
                            <Check
                              className={cn(
                                "mr-2 h-3 w-3",
                                !config.action?.dataTransfer?.additionalSources?.[0]?.fieldName
                                  ? "opacity-100"
                                  : "opacity-0",
                              )}
                            />
                            <span className="text-muted-foreground">선택 안 함 (전체 데이터 병합)</span>
                          </CommandItem>
                          {(mappingTargetColumns.length > 0 ? mappingTargetColumns : currentTableColumns).map((col) => (
                            <CommandItem
                              key={col.name}
                              value={`${col.label || ""} ${col.name}`}
                              onSelect={() => {
                                const currentSources = config.action?.dataTransfer?.additionalSources || [];
                                const newSources = [...currentSources];
                                if (newSources.length === 0) {
                                  newSources.push({ componentId: "", fieldName: col.name });
                                } else {
                                  newSources[0] = { ...newSources[0], fieldName: col.name };
                                }
                                onUpdateProperty("componentConfig.action.dataTransfer.additionalSources", newSources);
                              }}
                              className="text-xs"
                            >
                              <Check
                                className={cn(
                                  "mr-2 h-3 w-3",
                                  config.action?.dataTransfer?.additionalSources?.[0]?.fieldName === col.name
                                    ? "opacity-100"
                                    : "opacity-0",
                                )}
                              />
                              <span className="font-medium">{col.label || col.name}</span>
                              {col.label && col.label !== col.name && (
                                <span className="text-muted-foreground ml-1 text-[10px]">({col.name})</span>
                              )}
                            </CommandItem>
                          ))}
                        </CommandGroup>
                      </CommandList>
                    </Command>
                  </PopoverContent>
                </Popover>
                <p className="text-muted-foreground mt-1 text-xs">추가 데이터가 저장될 타겟 테이블 컬럼</p>
              </div>
            </div>
          </div>

          {/* 멀티 테이블 필드 매핑 */}
          <div className="space-y-3">
            <Label>필드 매핑 설정</Label>

            {/* 타겟 테이블 (공통) */}
            <div className="space-y-1">
              <Label className="text-xs">타겟 테이블</Label>
              <Popover>
                <PopoverTrigger asChild>
                  <Button variant="outline" role="combobox" className="h-8 w-full justify-between text-xs">
                    {config.action?.dataTransfer?.targetTable
                      ? availableTables.find((t) => t.name === config.action?.dataTransfer?.targetTable)?.label ||
                        config.action?.dataTransfer?.targetTable
                      : "타겟 테이블 선택"}
                    <ChevronsUpDown className="ml-2 h-3 w-3 shrink-0 opacity-50" />
                  </Button>
                </PopoverTrigger>
                <PopoverContent className="w-[250px] p-0" align="start">
                  <Command>
                    <CommandInput placeholder="테이블 검색..." className="h-8 text-xs" />
                    <CommandList>
                      <CommandEmpty className="py-2 text-center text-xs">테이블을 찾을 수 없습니다</CommandEmpty>
                      <CommandGroup>
                        {availableTables.map((table) => (
                          <CommandItem
                            key={table.name}
                            value={`${table.label} ${table.name}`}
                            onSelect={() => {
                              onUpdateProperty("componentConfig.action.dataTransfer.targetTable", table.name);
                            }}
                            className="text-xs"
                          >
                            <Check
                              className={cn(
                                "mr-2 h-3 w-3",
                                config.action?.dataTransfer?.targetTable === table.name ? "opacity-100" : "opacity-0",
                              )}
                            />
                            <span className="font-medium">{table.label}</span>
                            <span className="text-muted-foreground ml-1">({table.name})</span>
                          </CommandItem>
                        ))}
                      </CommandGroup>
                    </CommandList>
                  </Command>
                </PopoverContent>
              </Popover>
            </div>

            {/* 소스 테이블 매핑 그룹 */}
            <div className="space-y-2">
              <div className="flex items-center justify-between">
                <Label className="text-xs">소스 테이블별 매핑</Label>
                <Button
                  type="button"
                  variant="outline"
                  size="sm"
                  className="h-6 text-[10px]"
                  onClick={() => {
                    const currentMappings = config.action?.dataTransfer?.multiTableMappings || [];
                    onUpdateProperty("componentConfig.action.dataTransfer.multiTableMappings", [
                      ...currentMappings,
                      { sourceTable: "", mappingRules: [] },
                    ]);
                    setActiveMappingGroupIndex(currentMappings.length);
                  }}
                  disabled={!config.action?.dataTransfer?.targetTable}
                >
                  <Plus className="mr-1 h-3 w-3" />
                  소스 테이블 추가
                </Button>
              </div>
              <p className="text-muted-foreground text-[10px]">
                여러 소스 테이블에서 데이터를 전달할 때, 각 테이블별로 매핑 규칙을 설정합니다. 런타임에 소스 테이블을
                자동 감지합니다.
              </p>

              {!config.action?.dataTransfer?.targetTable ? (
                <div className="rounded-md border border-dashed p-3 text-center">
                  <p className="text-muted-foreground text-xs">먼저 타겟 테이블을 선택하세요.</p>
                </div>
              ) : !(config.action?.dataTransfer?.multiTableMappings || []).length ? (
                <div className="rounded-md border border-dashed p-3 text-center">
                  <p className="text-muted-foreground text-xs">매핑 그룹이 없습니다. 소스 테이블을 추가하세요.</p>
                </div>
              ) : (
                <div className="space-y-2">
                  {/* 소스 테이블 탭 */}
                  <div className="flex flex-wrap gap-1">
                    {(config.action?.dataTransfer?.multiTableMappings || []).map((group: any, gIdx: number) => (
                      <div key={gIdx} className="flex items-center gap-0.5">
                        <Button
                          type="button"
                          variant={activeMappingGroupIndex === gIdx ? "default" : "outline"}
                          size="sm"
                          className="h-6 text-[10px]"
                          onClick={() => setActiveMappingGroupIndex(gIdx)}
                        >
                          {group.sourceTable
                            ? availableTables.find((t) => t.name === group.sourceTable)?.label || group.sourceTable
                            : `그룹 ${gIdx + 1}`}
                          {group.mappingRules?.length > 0 && (
                            <span className="bg-primary/20 ml-1 rounded-full px-1 text-[9px]">
                              {group.mappingRules.length}
                            </span>
                          )}
                        </Button>
                        <Button
                          type="button"
                          variant="ghost"
                          size="icon"
                          className="text-destructive hover:bg-destructive/10 h-5 w-5"
                          onClick={() => {
                            const mappings = [...(config.action?.dataTransfer?.multiTableMappings || [])];
                            mappings.splice(gIdx, 1);
                            onUpdateProperty("componentConfig.action.dataTransfer.multiTableMappings", mappings);
                            if (activeMappingGroupIndex >= mappings.length) {
                              setActiveMappingGroupIndex(Math.max(0, mappings.length - 1));
                            }
                          }}
                        >
                          <X className="h-3 w-3" />
                        </Button>
                      </div>
                    ))}
                  </div>

                  {/* 활성 그룹 편집 영역 */}
                  {(() => {
                    const multiMappings = config.action?.dataTransfer?.multiTableMappings || [];
                    const activeGroup = multiMappings[activeMappingGroupIndex];
                    if (!activeGroup) return null;

                    const activeSourceTable = activeGroup.sourceTable || "";
                    const activeSourceColumns = mappingSourceColumnsMap[activeSourceTable] || [];
                    const activeRules: any[] = activeGroup.mappingRules || [];

                    const updateGroupField = (field: string, value: any) => {
                      const mappings = [...multiMappings];
                      mappings[activeMappingGroupIndex] = { ...mappings[activeMappingGroupIndex], [field]: value };
                      onUpdateProperty("componentConfig.action.dataTransfer.multiTableMappings", mappings);
                    };

                    return (
                      <div className="space-y-2 rounded-md border p-3">
                        {/* 소스 테이블 선택 */}
                        <div className="space-y-1">
                          <Label className="text-xs">소스 테이블</Label>
                          <Popover>
                            <PopoverTrigger asChild>
                              <Button variant="outline" role="combobox" className="h-8 w-full justify-between text-xs">
                                {activeSourceTable
                                  ? availableTables.find((t) => t.name === activeSourceTable)?.label ||
                                    activeSourceTable
                                  : "소스 테이블 선택"}
                                <ChevronsUpDown className="ml-2 h-3 w-3 shrink-0 opacity-50" />
                              </Button>
                            </PopoverTrigger>
                            <PopoverContent className="w-[250px] p-0" align="start">
                              <Command>
                                <CommandInput placeholder="테이블 검색..." className="h-8 text-xs" />
                                <CommandList>
                                  <CommandEmpty className="py-2 text-center text-xs">
                                    테이블을 찾을 수 없습니다
                                  </CommandEmpty>
                                  <CommandGroup>
                                    {availableTables.map((table) => (
                                      <CommandItem
                                        key={table.name}
                                        value={`${table.label} ${table.name}`}
                                        onSelect={async () => {
                                          updateGroupField("sourceTable", table.name);
                                          if (!mappingSourceColumnsMap[table.name]) {
                                            const cols = await loadMappingColumns(table.name);
                                            setMappingSourceColumnsMap((prev) => ({ ...prev, [table.name]: cols }));
                                          }
                                        }}
                                        className="text-xs"
                                      >
                                        <Check
                                          className={cn(
                                            "mr-2 h-3 w-3",
                                            activeSourceTable === table.name ? "opacity-100" : "opacity-0",
                                          )}
                                        />
                                        <span className="font-medium">{table.label}</span>
                                        <span className="text-muted-foreground ml-1">({table.name})</span>
                                      </CommandItem>
                                    ))}
                                  </CommandGroup>
                                </CommandList>
                              </Command>
                            </PopoverContent>
                          </Popover>
                        </div>

                        {/* 매핑 규칙 목록 */}
                        <div className="space-y-1">
                          <div className="flex items-center justify-between">
                            <Label className="text-[10px]">매핑 규칙</Label>
                            <Button
                              type="button"
                              variant="outline"
                              size="sm"
                              className="h-5 text-[10px]"
                              onClick={() => {
                                updateGroupField("mappingRules", [
                                  ...activeRules,
                                  { sourceField: "", targetField: "" },
                                ]);
                              }}
                              disabled={!activeSourceTable}
                            >
                              <Plus className="mr-1 h-3 w-3" />
                              추가
                            </Button>
                          </div>

                          {!activeSourceTable ? (
                            <p className="text-muted-foreground text-[10px]">소스 테이블을 먼저 선택하세요.</p>
                          ) : activeRules.length === 0 ? (
                            <p className="text-muted-foreground text-[10px]">매핑 없음 (동일 필드명 자동 매핑)</p>
                          ) : (
                            activeRules.map((rule: any, rIdx: number) => {
                              const popoverKeyS = `${activeMappingGroupIndex}-${rIdx}-s`;
                              const popoverKeyT = `${activeMappingGroupIndex}-${rIdx}-t`;
                              return (
                                <div key={rIdx} className="bg-background flex items-center gap-2 rounded-md border p-2">
                                  <div className="flex-1">
                                    <Popover
                                      open={mappingSourcePopoverOpen[popoverKeyS] || false}
                                      onOpenChange={(open) =>
                                        setMappingSourcePopoverOpen((prev) => ({ ...prev, [popoverKeyS]: open }))
                                      }
                                    >
                                      <PopoverTrigger asChild>
                                        <Button
                                          variant="outline"
                                          role="combobox"
                                          className="h-7 w-full justify-between text-xs"
                                        >
                                          {rule.sourceField
                                            ? activeSourceColumns.find((c) => c.name === rule.sourceField)?.label ||
                                              rule.sourceField
                                            : "소스 필드"}
                                          <ChevronsUpDown className="ml-1 h-3 w-3 shrink-0 opacity-50" />
                                        </Button>
                                      </PopoverTrigger>
                                      <PopoverContent className="w-[200px] p-0" align="start">
                                        <Command>
                                          <CommandInput placeholder="컬럼 검색..." className="h-8 text-xs" />
                                          <CommandList>
                                            <CommandEmpty className="py-2 text-center text-xs">컬럼 없음</CommandEmpty>
                                            <CommandGroup>
                                              {activeSourceColumns.map((col) => (
                                                <CommandItem
                                                  key={col.name}
                                                  value={`${col.label} ${col.name}`}
                                                  onSelect={() => {
                                                    const newRules = [...activeRules];
                                                    newRules[rIdx] = { ...newRules[rIdx], sourceField: col.name };
                                                    updateGroupField("mappingRules", newRules);
                                                    setMappingSourcePopoverOpen((prev) => ({
                                                      ...prev,
                                                      [popoverKeyS]: false,
                                                    }));
                                                  }}
                                                  className="text-xs"
                                                >
                                                  <Check
                                                    className={cn(
                                                      "mr-2 h-3 w-3",
                                                      rule.sourceField === col.name ? "opacity-100" : "opacity-0",
                                                    )}
                                                  />
                                                  <span>{col.label}</span>
                                                  {col.label !== col.name && (
                                                    <span className="text-muted-foreground ml-1">({col.name})</span>
                                                  )}
                                                </CommandItem>
                                              ))}
                                            </CommandGroup>
                                          </CommandList>
                                        </Command>
                                      </PopoverContent>
                                    </Popover>
                                  </div>

                                  <span className="text-muted-foreground text-xs">→</span>

                                  <div className="flex-1">
                                    <Popover
                                      open={mappingTargetPopoverOpen[popoverKeyT] || false}
                                      onOpenChange={(open) =>
                                        setMappingTargetPopoverOpen((prev) => ({ ...prev, [popoverKeyT]: open }))
                                      }
                                    >
                                      <PopoverTrigger asChild>
                                        <Button
                                          variant="outline"
                                          role="combobox"
                                          className="h-7 w-full justify-between text-xs"
                                        >
                                          {rule.targetField
                                            ? mappingTargetColumns.find((c) => c.name === rule.targetField)?.label ||
                                              rule.targetField
                                            : "타겟 필드"}
                                          <ChevronsUpDown className="ml-1 h-3 w-3 shrink-0 opacity-50" />
                                        </Button>
                                      </PopoverTrigger>
                                      <PopoverContent className="w-[200px] p-0" align="start">
                                        <Command>
                                          <CommandInput placeholder="컬럼 검색..." className="h-8 text-xs" />
                                          <CommandList>
                                            <CommandEmpty className="py-2 text-center text-xs">컬럼 없음</CommandEmpty>
                                            <CommandGroup>
                                              {mappingTargetColumns.map((col) => (
                                                <CommandItem
                                                  key={col.name}
                                                  value={`${col.label} ${col.name}`}
                                                  onSelect={() => {
                                                    const newRules = [...activeRules];
                                                    newRules[rIdx] = { ...newRules[rIdx], targetField: col.name };
                                                    updateGroupField("mappingRules", newRules);
                                                    setMappingTargetPopoverOpen((prev) => ({
                                                      ...prev,
                                                      [popoverKeyT]: false,
                                                    }));
                                                  }}
                                                  className="text-xs"
                                                >
                                                  <Check
                                                    className={cn(
                                                      "mr-2 h-3 w-3",
                                                      rule.targetField === col.name ? "opacity-100" : "opacity-0",
                                                    )}
                                                  />
                                                  <span>{col.label}</span>
                                                  {col.label !== col.name && (
                                                    <span className="text-muted-foreground ml-1">({col.name})</span>
                                                  )}
                                                </CommandItem>
                                              ))}
                                            </CommandGroup>
                                          </CommandList>
                                        </Command>
                                      </PopoverContent>
                                    </Popover>
                                  </div>

                                  <Button
                                    type="button"
                                    variant="ghost"
                                    size="icon"
                                    className="text-destructive hover:bg-destructive/10 h-7 w-7"
                                    onClick={() => {
                                      const newRules = [...activeRules];
                                      newRules.splice(rIdx, 1);
                                      updateGroupField("mappingRules", newRules);
                                    }}
                                  >
                                    <X className="h-3 w-3" />
                                  </Button>
                                </div>
                              );
                            })
                          )}
                        </div>
                      </div>
                    );
                  })()}
                </div>
              )}
            </div>
          </div>

          <div className="rounded-md bg-primary/10 p-3 dark:bg-primary/15">
            <p className="text-xs text-primary dark:text-primary/60">
              <strong>사용 방법:</strong>
              <br />
              1. 소스 컴포넌트에서 데이터를 선택합니다
              <br />
              2. 소스 테이블별로 필드 매핑 규칙을 설정합니다
              <br />
              3. 이 버튼을 클릭하면 소스 테이블을 자동 감지하여 매핑된 데이터가 타겟으로 전달됩니다
            </p>
          </div>
        </div>
      )}

      {/* 🆕 즉시 저장(quickInsert) 액션 설정 */}
      {component.componentConfig?.action?.type === "quickInsert" && (
        <QuickInsertConfigSection
          component={component}
          onUpdateProperty={onUpdateProperty}
          allComponents={allComponents}
          currentTableName={currentTableName}
        />
      )}

      {/* 결재 요청(approval) 액션 설정 */}
      {localInputs.actionType === "approval" && (
        <div className="bg-muted/50 mt-4 space-y-4 rounded-lg border p-4">
          <h4 className="text-foreground text-sm font-medium">결재 요청 설정</h4>
          <p className="text-muted-foreground text-xs">
            버튼 클릭 시 결재 요청 모달이 열립니다. 결재 유형을 선택하면 기본 결재선이 자동으로 세팅됩니다.
          </p>

          <div>
            <Label htmlFor="approval-definition" className="text-xs sm:text-sm">
              결재 유형
            </Label>
            <Select
              value={String(component.componentConfig?.action?.approvalDefinitionId || "")}
              onValueChange={(value) => {
                onUpdateProperty(
                  "componentConfig.action.approvalDefinitionId",
                  value === "none" ? null : Number(value),
                );
              }}
            >
              <SelectTrigger className="h-8 text-xs sm:h-10 sm:text-sm">
                <SelectValue placeholder={approvalDefinitionsLoading ? "로딩 중..." : "결재 유형 선택 (선택사항)"} />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="none">유형 없음 (직접 설정)</SelectItem>
                {approvalDefinitions.map((def) => (
                  <SelectItem key={def.definition_id} value={String(def.definition_id)}>
                    {def.definition_name}
                    {def.description ? ` - ${def.description}` : ""}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
            <p className="text-muted-foreground mt-1 text-[10px] sm:text-xs">
              결재 유형을 선택하면 기본 결재선 템플릿이 자동 적용됩니다
            </p>
          </div>

          <div>
            <Label htmlFor="approval-target-table" className="text-xs sm:text-sm">
              대상 테이블
            </Label>
            <Input
              id="approval-target-table"
              placeholder={currentTableName || "예: purchase_orders"}
              value={component.componentConfig?.action?.approvalTargetTable || currentTableName || ""}
              onChange={(e) => onUpdateProperty("componentConfig.action.approvalTargetTable", e.target.value)}
              className="h-8 text-xs sm:h-10 sm:text-sm"
              readOnly={!!currentTableName && !component.componentConfig?.action?.approvalTargetTable}
            />
            <p className="text-muted-foreground mt-1 text-[10px] sm:text-xs">
              {currentTableName
                ? `현재 화면 테이블 "${currentTableName}" 자동 적용됨`
                : "결재 대상 레코드가 저장된 테이블명"}
            </p>
          </div>

          <div>
            <Label htmlFor="approval-record-id-field" className="text-xs sm:text-sm">
              레코드 ID 필드명
            </Label>
            <Input
              id="approval-record-id-field"
              placeholder="예: id, purchase_id"
              value={component.componentConfig?.action?.approvalRecordIdField || "id"}
              onChange={(e) => onUpdateProperty("componentConfig.action.approvalRecordIdField", e.target.value)}
              className="h-8 text-xs sm:h-10 sm:text-sm"
            />
            <p className="text-muted-foreground mt-1 text-[10px] sm:text-xs">현재 선택된 레코드의 PK 컬럼명</p>
          </div>
        </div>
      )}

      {/* 🆕 이벤트 발송 액션 설정 */}
      {localInputs.actionType === "event" && (
        <div className="bg-muted/50 mt-4 space-y-4 rounded-lg border p-4">
          <h4 className="text-foreground text-sm font-medium">이벤트 발송 설정</h4>
          <p className="text-muted-foreground text-xs">
            버튼 클릭 시 V2 이벤트 버스를 통해 이벤트를 발송합니다. 다른 컴포넌트나 서비스에서 이 이벤트를 수신하여
            처리할 수 있습니다.
          </p>

          <div>
            <Label htmlFor="event-name">이벤트 이름</Label>
            <Select
              value={component.componentConfig?.action?.eventConfig?.eventName || ""}
              onValueChange={(value) => {
                onUpdateProperty("componentConfig.action.eventConfig.eventName", value);
              }}
            >
              <SelectTrigger className="h-8 text-xs">
                <SelectValue placeholder="이벤트 선택" />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="SCHEDULE_GENERATE_REQUEST">스케줄 자동 생성 요청</SelectItem>
                <SelectItem value="TABLE_REFRESH">테이블 새로고침</SelectItem>
                <SelectItem value="DATA_CHANGED">데이터 변경 알림</SelectItem>
              </SelectContent>
            </Select>
          </div>

          {component.componentConfig?.action?.eventConfig?.eventName === "SCHEDULE_GENERATE_REQUEST" && (
            <div className="border-primary/20 space-y-3 border-l-2 pl-4">
              <div>
                <Label>스케줄 유형</Label>
                <Select
                  value={component.componentConfig?.action?.eventConfig?.eventPayload?.scheduleType || "PRODUCTION"}
                  onValueChange={(value) => {
                    onUpdateProperty("componentConfig.action.eventConfig.eventPayload.scheduleType", value);
                  }}
                >
                  <SelectTrigger className="h-8 text-xs">
                    <SelectValue placeholder="스케줄 유형 선택" />
                  </SelectTrigger>
                  <SelectContent>
                    <SelectItem value="PRODUCTION">생산 스케줄</SelectItem>
                    <SelectItem value="DELIVERY">배송 스케줄</SelectItem>
                    <SelectItem value="MAINTENANCE">정비 스케줄</SelectItem>
                    <SelectItem value="CUSTOM">커스텀</SelectItem>
                  </SelectContent>
                </Select>
              </div>

              <div>
                <Label>리드타임 (일)</Label>
                <Input
                  type="number"
                  className="h-8 text-xs"
                  placeholder="3"
                  value={
                    component.componentConfig?.action?.eventConfig?.eventPayload?.config?.scheduling?.leadTimeDays || 3
                  }
                  onChange={(e) => {
                    onUpdateProperty(
                      "componentConfig.action.eventConfig.eventPayload.config.scheduling.leadTimeDays",
                      parseInt(e.target.value) || 3,
                    );
                  }}
                />
              </div>

              <div>
                <Label>일일 최대 생산량</Label>
                <Input
                  type="number"
                  className="h-8 text-xs"
                  placeholder="100"
                  value={
                    component.componentConfig?.action?.eventConfig?.eventPayload?.config?.scheduling
                      ?.maxDailyCapacity || 100
                  }
                  onChange={(e) => {
                    onUpdateProperty(
                      "componentConfig.action.eventConfig.eventPayload.config.scheduling.maxDailyCapacity",
                      parseInt(e.target.value) || 100,
                    );
                  }}
                />
              </div>

              <div className="rounded-md bg-primary/10 p-2 dark:bg-primary/10">
                <p className="text-xs text-primary dark:text-primary/70">
                  <strong>동작 방식:</strong> 테이블에서 선택된 데이터를 기반으로 스케줄을 자동 생성합니다. 생성 전
                  미리보기 확인 다이얼로그가 표시됩니다.
                </p>
              </div>
            </div>
          )}
        </div>
      )}
    </div>
  );
};

/**
 * 마스터-디테일 엑셀 업로드 설정 컴포넌트
 * 분할 패널 + column_labels에서 관계를 자동 감지 (채번은 테이블 타입 관리에서 자동 감지)
 */
const MasterDetailExcelUploadConfig: React.FC<{
  config: any;
  onUpdateProperty: (path: string, value: any) => void;
  allComponents: ComponentData[];
}> = ({ config, onUpdateProperty, allComponents }) => {
  const [relationInfo, setRelationInfo] = useState<{
    masterTable: string;
    detailTable: string;
    masterKeyColumn: string;
    detailFkColumn: string;
  } | null>(null);
  const [loading, setLoading] = useState(false);
  const [masterColumns, setMasterColumns] = useState<
    Array<{
      columnName: string;
      columnLabel: string;
      inputType: string;
      referenceTable?: string;
      referenceColumn?: string;
      displayColumn?: string;
    }>
  >([]);
  // 참조 테이블별 컬럼 목록 캐시 (컬럼명 + 라벨)
  const [refTableColumns, setRefTableColumns] = useState<Record<string, Array<{ name: string; label: string }>>>({});

  // 마스터-디테일 설정
  const masterDetailConfig = config.action?.masterDetailExcel || {};

  // 분할 패널에서 마스터/디테일 테이블명 자동 감지
  const splitPanelInfo = useMemo(() => {
    const findSplitPanel = (components: any[]): any => {
      for (const comp of components) {
        const compId = comp.componentId || comp.componentType;
        if (compId === "split-panel-layout") {
          return comp.componentConfig;
        }
        if (comp.children && comp.children.length > 0) {
          const found = findSplitPanel(comp.children);
          if (found) return found;
        }
      }
      return null;
    };
    return findSplitPanel(allComponents as any[]);
  }, [allComponents]);

  const masterTable = splitPanelInfo?.leftPanel?.tableName || "";
  const detailTable = splitPanelInfo?.rightPanel?.tableName || "";

  // 마스터 테이블 컬럼 로드
  useEffect(() => {
    if (!masterTable) {
      setMasterColumns([]);
      return;
    }

    const loadMasterColumns = async () => {
      try {
        const { apiClient } = await import("@/lib/api/client");
        const response = await apiClient.get(`/table-management/tables/${masterTable}/columns`);
        if (response.data?.success && response.data?.data?.columns) {
          const cols = response.data.data.columns.map((col: any) => ({
            columnName: col.columnName || col.column_name,
            columnLabel: col.displayName || col.columnLabel || col.column_label || col.columnName || col.column_name,
            inputType: col.inputType || col.input_type || "text",
            referenceTable: col.referenceTable || col.reference_table,
            referenceColumn: col.referenceColumn || col.reference_column,
            displayColumn: col.displayColumn || col.display_column,
          }));
          setMasterColumns(cols);
        }
      } catch (error) {
        console.error("마스터 테이블 컬럼 로드 실패:", error);
      }
    };
    loadMasterColumns();
  }, [masterTable]);

  // 선택된 엔티티 필드들의 참조 테이블 컬럼 로드
  useEffect(() => {
    const entityFields = (masterDetailConfig.masterSelectFields || []).filter(
      (f: any) => f.inputType === "entity" && f.referenceTable,
    );

    const loadRefTableColumns = async () => {
      const { apiClient } = await import("@/lib/api/client");

      for (const field of entityFields) {
        // 이미 로드된 테이블은 스킵
        if (refTableColumns[field.referenceTable]) continue;

        try {
          const response = await apiClient.get(`/table-management/tables/${field.referenceTable}/columns`);
          if (response.data?.success && response.data?.data?.columns) {
            const cols = response.data.data.columns.map((c: any) => ({
              name: c.columnName || c.column_name,
              label: c.displayName || c.columnLabel || c.column_label || c.columnName || c.column_name,
            }));
            setRefTableColumns((prev) => ({
              ...prev,
              [field.referenceTable]: cols,
            }));
          }
        } catch (error) {
          console.error("참조 테이블 컬럼 로드 실패:", field.referenceTable, error);
        }
      }
    };

    if (entityFields.length > 0) {
      loadRefTableColumns();
    }
  }, [masterDetailConfig.masterSelectFields, refTableColumns]);

  // column_labels에서 FK 관계 자동 감지
  useEffect(() => {
    if (!masterTable || !detailTable) {
      setRelationInfo(null);
      return;
    }

    const loadRelationInfo = async () => {
      setLoading(true);
      try {
        const { apiClient } = await import("@/lib/api/client");
        // 디테일 테이블의 컬럼 정보 조회 (referenceTable, referenceColumn 포함)
        const response = await apiClient.get(`/table-management/tables/${detailTable}/columns`);

        if (response.data?.success && response.data?.data?.columns) {
          const columns = response.data.data.columns;
          // referenceTable이 마스터 테이블인 컬럼 찾기
          const fkColumn = columns.find((col: any) => col.referenceTable === masterTable);

          if (fkColumn) {
            const detailFk = fkColumn.columnName || fkColumn.column_name;
            const masterKey = fkColumn.referenceColumn || fkColumn.reference_column;

            setRelationInfo({
              masterTable,
              detailTable,
              masterKeyColumn: masterKey,
              detailFkColumn: detailFk,
            });

            // 설정에 자동으로 저장
            onUpdateProperty("componentConfig.action.masterDetailExcel", {
              ...masterDetailConfig,
              masterTable,
              detailTable,
              masterKeyColumn: masterKey,
              detailFkColumn: detailFk,
            });
          } else {
            setRelationInfo(null);
          }
        }
      } catch (error) {
        console.error("FK 관계 로드 실패:", error);
        setRelationInfo(null);
      } finally {
        setLoading(false);
      }
    };

    loadRelationInfo();
  }, [masterTable, detailTable]);

  const updateMasterDetailConfig = (updates: Record<string, any>) => {
    onUpdateProperty("componentConfig.action.masterDetailExcel", {
      ...masterDetailConfig,
      ...updates,
    });
  };

  // 분할 패널이 없으면 표시하지 않음
  if (!splitPanelInfo) {
    return (
      <div className="space-y-2 border-t pt-4">
        <p className="text-muted-foreground text-xs">
          이 화면에 분할 패널이 없습니다. 마스터-디테일 업로드는 분할 패널 화면에서만 사용할 수 있습니다.
        </p>
      </div>
    );
  }

  return (
    <div className="space-y-4 border-t pt-4">
      <h5 className="text-muted-foreground text-xs font-medium">마스터-디테일 설정 (자동 감지)</h5>

      {/* 자동 감지된 정보 표시 */}
      <div className="rounded-md bg-muted p-3 dark:bg-foreground">
        <p className="mb-2 text-xs font-medium">분할 패널에서 감지된 정보:</p>
        <div className="grid grid-cols-2 gap-2 text-xs">
          <div>
            <span className="text-muted-foreground">마스터:</span>{" "}
            <span className="font-medium">{masterTable || "-"}</span>
          </div>
          <div>
            <span className="text-muted-foreground">디테일:</span>{" "}
            <span className="font-medium">{detailTable || "-"}</span>
          </div>
        </div>

        {loading ? (
          <p className="text-muted-foreground mt-2 text-xs">FK 관계 조회 중...</p>
        ) : relationInfo ? (
          <div className="mt-2 grid grid-cols-2 gap-2 text-xs">
            <div>
              <span className="text-muted-foreground">마스터 키:</span>{" "}
              <span className="font-medium text-emerald-600">{relationInfo.masterKeyColumn}</span>
            </div>
            <div>
              <span className="text-muted-foreground">디테일 FK:</span>{" "}
              <span className="font-medium text-emerald-600">{relationInfo.detailFkColumn}</span>
            </div>
          </div>
        ) : (
          <p className="mt-2 text-xs text-amber-600">
            FK 관계를 찾을 수 없습니다. 테이블 타입관리에서 reference_table을 설정해주세요.
          </p>
        )}
      </div>

      {/* 마스터 키 자동 생성 안내 */}
      {relationInfo && (
        <p className="text-muted-foreground border-t pt-2 text-xs">
          마스터 테이블의 <strong>{relationInfo.masterKeyColumn}</strong> 값은 테이블 타입 관리에서 설정된 채번 규칙으로
          자동 생성됩니다.
        </p>
      )}

      {/* 마스터 필드 선택 - 사용자가 엑셀 업로드 시 입력할 필드 */}
      {relationInfo && masterColumns.length > 0 && (
        <div>
          <Label className="text-xs">사용자 입력 필드 (마스터)</Label>
          <p className="text-muted-foreground mb-2 text-xs">
            엑셀 업로드 시 사용자가 직접 선택/입력할 마스터 테이블 필드를 선택하세요.
          </p>
          <div className="max-h-40 space-y-1 overflow-y-auto rounded-md border p-2">
            {masterColumns
              .filter((col) => col.columnName !== relationInfo.masterKeyColumn) // 채번으로 자동 생성되는 키는 제외
              .map((col) => {
                const selectedFields = masterDetailConfig.masterSelectFields || [];
                const isSelected = selectedFields.some((f: any) => f.columnName === col.columnName);
                return (
                  <div key={col.columnName} className="flex items-center gap-2">
                    <input
                      type="checkbox"
                      id={`master-field-${col.columnName}`}
                      checked={isSelected}
                      onChange={(e) => {
                        const checked = e.target.checked;
                        let newFields = [...selectedFields];
                        if (checked) {
                          newFields.push({
                            columnName: col.columnName,
                            columnLabel: col.columnLabel,
                            inputType: col.inputType,
                            referenceTable: col.referenceTable,
                            referenceColumn: col.referenceColumn,
                            displayColumn: col.displayColumn,
                            required: true,
                          });
                        } else {
                          newFields = newFields.filter((f: any) => f.columnName !== col.columnName);
                        }
                        updateMasterDetailConfig({ masterSelectFields: newFields });
                      }}
                      className="h-4 w-4 rounded border-input"
                    />
                    <label htmlFor={`master-field-${col.columnName}`} className="flex-1 cursor-pointer text-xs">
                      {col.columnLabel}
                      <span className="text-muted-foreground ml-1">({col.columnName})</span>
                      {col.inputType === "entity" && <span className="ml-1 text-primary">[엔티티]</span>}
                    </label>
                  </div>
                );
              })}
          </div>
          {(masterDetailConfig.masterSelectFields?.length || 0) > 0 && (
            <p className="text-muted-foreground mt-1 text-xs">
              선택된 필드: {masterDetailConfig.masterSelectFields.length}개
            </p>
          )}

          {/* 엔티티 필드의 표시컬럼 설정 */}
          {masterDetailConfig.masterSelectFields?.filter((f: any) => f.inputType === "entity").length > 0 && (
            <div className="mt-3 space-y-2 border-t pt-3">
              <Label className="text-xs">엔티티 필드 표시컬럼 설정</Label>
              {masterDetailConfig.masterSelectFields
                .filter((f: any) => f.inputType === "entity")
                .map((field: any) => {
                  const availableColumns = refTableColumns[field.referenceTable] || [];
                  return (
                    <div key={`display-${field.columnName}`} className="flex items-center gap-2">
                      <span className="w-24 truncate text-xs">{field.columnLabel}:</span>
                      <Select
                        value={field.displayColumn || ""}
                        onValueChange={(value) => {
                          const newFields = masterDetailConfig.masterSelectFields.map((f: any) =>
                            f.columnName === field.columnName ? { ...f, displayColumn: value } : f,
                          );
                          updateMasterDetailConfig({ masterSelectFields: newFields });
                        }}
                      >
                        <SelectTrigger className="h-7 flex-1 text-xs">
                          <SelectValue placeholder="표시컬럼 선택" />
                        </SelectTrigger>
                        <SelectContent>
                          {availableColumns.length === 0 ? (
                            <SelectItem value="__loading__" disabled>
                              {field.referenceTable ? "로딩 중..." : "참조 테이블 없음"}
                            </SelectItem>
                          ) : (
                            availableColumns.map((col) => (
                              <SelectItem key={col.name} value={col.name} className="text-xs">
                                {col.label}
                              </SelectItem>
                            ))
                          )}
                        </SelectContent>
                      </Select>
                    </div>
                  );
                })}
              <p className="text-muted-foreground text-xs">참조 테이블에서 사용자에게 표시할 컬럼을 선택하세요.</p>
            </div>
          )}
        </div>
      )}
    </div>
  );
};

/**
 * 엑셀 업로드 채번 규칙 안내 (테이블 타입 관리에서 자동 감지)
 */
const ExcelNumberingRuleInfo: React.FC = () => {
  return (
    <div className="border-t pt-3">
      <Label className="text-xs">채번 규칙</Label>
      <p className="text-muted-foreground mt-1 text-xs">
        테이블 타입 관리에서 "채번" 타입으로 설정된 컬럼의 채번 규칙이 업로드 시 자동으로 적용됩니다.
      </p>
    </div>
  );
};

/**
 * 엑셀 업로드 후 제어 실행 설정 (단일 테이블/마스터-디테일 모두 사용 가능)
 */
const ExcelAfterUploadControlConfig: React.FC<{
  config: { afterUploadFlows?: Array<{ flowId: string; order: number }> };
  updateConfig: (updates: { afterUploadFlows?: Array<{ flowId: string; order: number }> }) => void;
}> = ({ config, updateConfig }) => {
  const [nodeFlows, setNodeFlows] = useState<Array<{ flowId: number; flowName: string; flowDescription?: string }>>([]);
  const [flowSelectOpen, setFlowSelectOpen] = useState(false);
  const [isLoading, setIsLoading] = useState(false);

  const selectedFlows = config.afterUploadFlows || [];

  // 노드 플로우 목록 로드
  useEffect(() => {
    const loadNodeFlows = async () => {
      setIsLoading(true);
      try {
        const { apiClient } = await import("@/lib/api/client");
        const response = await apiClient.get("/dataflow/node-flows");
        if (response.data?.success && response.data?.data) {
          setNodeFlows(response.data.data);
        }
      } catch (error) {
        console.error("노드 플로우 목록 로드 실패:", error);
      } finally {
        setIsLoading(false);
      }
    };

    loadNodeFlows();
  }, []);

  const addFlow = (flowId: string) => {
    if (selectedFlows.some((f) => f.flowId === flowId)) return;
    const newFlows = [...selectedFlows, { flowId, order: selectedFlows.length + 1 }];
    updateConfig({ afterUploadFlows: newFlows });
    setFlowSelectOpen(false);
  };

  const removeFlow = (flowId: string) => {
    const newFlows = selectedFlows.filter((f) => f.flowId !== flowId).map((f, idx) => ({ ...f, order: idx + 1 }));
    updateConfig({ afterUploadFlows: newFlows });
  };

  const moveUp = (index: number) => {
    if (index === 0) return;
    const newFlows = [...selectedFlows];
    [newFlows[index - 1], newFlows[index]] = [newFlows[index], newFlows[index - 1]];
    updateConfig({ afterUploadFlows: newFlows.map((f, idx) => ({ ...f, order: idx + 1 })) });
  };

  const moveDown = (index: number) => {
    if (index === selectedFlows.length - 1) return;
    const newFlows = [...selectedFlows];
    [newFlows[index], newFlows[index + 1]] = [newFlows[index + 1], newFlows[index]];
    updateConfig({ afterUploadFlows: newFlows.map((f, idx) => ({ ...f, order: idx + 1 })) });
  };

  const availableFlows = nodeFlows.filter((f) => !selectedFlows.some((s) => s.flowId === String(f.flowId)));

  return (
    <div className="border-t pt-3">
      <Label className="text-xs">업로드 후 제어 실행</Label>
      <p className="text-muted-foreground mb-2 text-xs">엑셀 업로드 완료 후 순서대로 실행할 제어를 추가하세요.</p>

      {selectedFlows.length > 0 && (
        <div className="mb-2 space-y-1">
          {selectedFlows.map((selected, index) => {
            const flow = nodeFlows.find((f) => String(f.flowId) === selected.flowId);
            return (
              <div key={selected.flowId} className="flex items-center gap-1 rounded border bg-white p-1.5">
                <span className="text-muted-foreground w-5 text-center text-xs">{index + 1}</span>
                <span className="flex-1 truncate text-xs">{flow?.flowName || `Flow ${selected.flowId}`}</span>
                <Button
                  variant="ghost"
                  size="sm"
                  className="h-5 w-5 p-0"
                  onClick={() => moveUp(index)}
                  disabled={index === 0}
                >
                  <ChevronUp className="h-3 w-3" />
                </Button>
                <Button
                  variant="ghost"
                  size="sm"
                  className="h-5 w-5 p-0"
                  onClick={() => moveDown(index)}
                  disabled={index === selectedFlows.length - 1}
                >
                  <ChevronDown className="h-3 w-3" />
                </Button>
                <Button
                  variant="ghost"
                  size="sm"
                  className="h-5 w-5 p-0 text-destructive"
                  onClick={() => removeFlow(selected.flowId)}
                >
                  <X className="h-3 w-3" />
                </Button>
              </div>
            );
          })}
        </div>
      )}

      <Popover open={flowSelectOpen} onOpenChange={setFlowSelectOpen}>
        <PopoverTrigger asChild>
          <Button
            variant="outline"
            className="h-8 w-full justify-between text-xs"
            disabled={isLoading || availableFlows.length === 0}
          >
            {isLoading ? "로딩 중..." : availableFlows.length === 0 ? "추가 가능한 제어 없음" : "제어 추가..."}
            <Plus className="ml-2 h-4 w-4" />
          </Button>
        </PopoverTrigger>
        <PopoverContent className="w-[300px] p-0" align="start">
          <Command>
            <CommandInput placeholder="제어 검색..." className="text-xs" />
            <CommandList>
              <CommandEmpty className="py-2 text-center text-xs">검색 결과 없음</CommandEmpty>
              <CommandGroup>
                {availableFlows.map((flow) => (
                  <CommandItem
                    key={flow.flowId}
                    value={flow.flowName}
                    onSelect={() => addFlow(String(flow.flowId))}
                    className="text-xs"
                  >
                    <div className="flex flex-col">
                      <span>{flow.flowName}</span>
                      {flow.flowDescription && (
                        <span className="text-muted-foreground text-[10px]">{flow.flowDescription}</span>
                      )}
                    </div>
                  </CommandItem>
                ))}
              </CommandGroup>
            </CommandList>
          </Command>
        </PopoverContent>
      </Popover>

      {selectedFlows.length > 0 && (
        <p className="text-muted-foreground mt-1 text-xs">
          업로드 완료 후 위 순서대로 {selectedFlows.length}개의 제어가 실행됩니다.
        </p>
      )}
    </div>
  );
};

/**
 * 엑셀 업로드 설정 섹션 컴포넌트
 * 마스터-디테일 설정은 분할 패널 자동 감지
 */
const ExcelUploadConfigSection: React.FC<{
  config: any;
  onUpdateProperty: (path: string, value: any) => void;
  allComponents: ComponentData[];
  currentTableName?: string; // 현재 화면의 테이블명 (ButtonConfigPanel에서 전달)
}> = ({ config, onUpdateProperty, allComponents, currentTableName: propTableName }) => {
  // 엑셀 업로드 설정 상태 관리 (채번은 테이블 타입 관리에서 자동 감지)
  const [excelUploadConfig, setExcelUploadConfig] = useState<{
    afterUploadFlows?: Array<{ flowId: string; order: number }>;
  }>({
    afterUploadFlows: config.action?.excelAfterUploadFlows || [],
  });

  // 분할 패널 감지
  const splitPanelInfo = useMemo(() => {
    const findSplitPanel = (components: any[]): any => {
      for (const comp of components) {
        const compId = comp.componentId || comp.componentType;
        if (compId === "split-panel-layout") {
          return comp.componentConfig;
        }
        if (comp.children && comp.children.length > 0) {
          const found = findSplitPanel(comp.children);
          if (found) return found;
        }
      }
      return null;
    };
    return findSplitPanel(allComponents as any[]);
  }, [allComponents]);

  const hasSplitPanel = !!splitPanelInfo;

  // 단일 테이블 감지 (props 우선, 없으면 컴포넌트에서 탐색)
  const singleTableName = useMemo(() => {
    if (hasSplitPanel) return undefined;

    // props로 전달된 테이블명 우선 사용
    if (propTableName) return propTableName;

    // 컴포넌트에서 테이블명 탐색
    const findTableName = (components: any[]): string | undefined => {
      for (const comp of components) {
        const compId = comp.componentId || comp.componentType;
        const compConfig = comp.componentConfig || comp.config || comp;

        // 테이블 패널이나 데이터 테이블에서 테이블명 찾기
        if (
          compId === "table-panel" ||
          compId === "data-table" ||
          compId === "table-list" ||
          compId === "simple-table"
        ) {
          const tableName = compConfig?.tableName || compConfig?.table;
          if (tableName) return tableName;
        }

        // 폼 컴포넌트에서 테이블명 찾기
        if (compId === "form-panel" || compId === "input-form" || compId === "form" || compId === "detail-form") {
          const tableName = compConfig?.tableName || compConfig?.table;
          if (tableName) return tableName;
        }

        // 범용적으로 tableName 속성이 있는 컴포넌트 찾기
        if (compConfig?.tableName) {
          return compConfig.tableName;
        }

        if (comp.children && comp.children.length > 0) {
          const found = findTableName(comp.children);
          if (found) return found;
        }
      }
      return undefined;
    };
    return findTableName(allComponents as any[]);
  }, [allComponents, hasSplitPanel, propTableName]);

  // 디버깅: 감지된 테이블명 로그
  useEffect(() => {
    console.log(
      "[ExcelUploadConfigSection] 분할 패널:",
      hasSplitPanel,
      "단일 테이블:",
      singleTableName,
      "(props:",
      propTableName,
      ")",
    );
  }, [hasSplitPanel, singleTableName, propTableName]);

  // 설정 업데이트 함수 (채번은 테이블 타입 관리에서 자동 감지되므로 제어 실행만 관리)
  const updateExcelUploadConfig = (updates: Partial<typeof excelUploadConfig>) => {
    const newConfig = { ...excelUploadConfig, ...updates };
    setExcelUploadConfig(newConfig);

    if (updates.afterUploadFlows !== undefined) {
      onUpdateProperty("componentConfig.action.excelAfterUploadFlows", updates.afterUploadFlows);
    }
  };

  // config 변경 시 로컬 상태 동기화
  useEffect(() => {
    setExcelUploadConfig({
      afterUploadFlows: config.action?.excelAfterUploadFlows || [],
    });
  }, [config.action?.excelAfterUploadFlows]);

  return (
    <div className="bg-muted/50 mt-4 space-y-4 rounded-lg border p-4">
      <h4 className="text-foreground text-sm font-medium">엑셀 업로드 설정</h4>

      <div>
        <Label htmlFor="excel-upload-mode">업로드 모드</Label>
        <Select
          value={config.action?.excelUploadMode || "insert"}
          onValueChange={(value) => onUpdateProperty("componentConfig.action.excelUploadMode", value)}
        >
          <SelectTrigger className="h-8 text-xs">
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="insert">신규 삽입 (INSERT)</SelectItem>
            <SelectItem value="update">기존 수정 (UPDATE)</SelectItem>
            <SelectItem value="upsert">삽입/수정 (UPSERT)</SelectItem>
          </SelectContent>
        </Select>
      </div>

      {(config.action?.excelUploadMode === "update" || config.action?.excelUploadMode === "upsert") && (
        <div>
          <Label htmlFor="excel-key-column">
            키 컬럼명 <span className="text-destructive">*</span>
          </Label>
          <Input
            id="excel-key-column"
            placeholder="예: id, code"
            value={config.action?.excelKeyColumn || ""}
            onChange={(e) => onUpdateProperty("componentConfig.action.excelKeyColumn", e.target.value)}
            className="h-8 text-xs"
          />
          <p className="text-muted-foreground mt-1 text-xs">UPDATE/UPSERT 시 기준이 되는 컬럼명</p>
        </div>
      )}

      {/* 채번 규칙 안내 (테이블 타입 관리에서 자동 감지) */}
      <ExcelNumberingRuleInfo />

      {/* 업로드 후 제어 실행 (항상 표시) */}
      <ExcelAfterUploadControlConfig config={excelUploadConfig} updateConfig={updateExcelUploadConfig} />

      {/* 마스터-디테일 설정 (분할 패널 자동 감지) */}
      <MasterDetailExcelUploadConfig
        config={config}
        onUpdateProperty={onUpdateProperty}
        allComponents={allComponents}
      />
    </div>
  );
};
