"use client";

import React, { useState, useCallback, useEffect, useMemo, useRef } from "react";
import { ComponentRendererProps } from "../../types";
import { SplitPanelLayoutConfig } from "./types";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import {
  Plus,
  Search,
  GripVertical,
  Loader2,
  ChevronDown,
  ChevronUp,
  Save,
  ChevronRight,
  Pencil,
  Trash2,
} from "lucide-react";
import { dataApi } from "@/lib/api/data";
import { entityJoinApi } from "@/lib/api/entityJoin";
import { useToast } from "@/hooks/use-toast";
import { tableTypeApi } from "@/lib/api/screen";
import { apiClient, getFullImageUrl } from "@/lib/api/client";
import { getFilePreviewUrl } from "@/lib/api/file";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogFooter,
  DialogDescription,
} from "@/components/ui/dialog";
import { Label } from "@/components/ui/label";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { useTableOptions } from "@/contexts/TableOptionsContext";
import { TableFilter, ColumnVisibility, GroupSumConfig } from "@/types/table-options";
import { useAuth } from "@/hooks/useAuth";
import { useSplitPanel } from "./SplitPanelContext";

// 테이블 셀 이미지 썸네일 컴포넌트
const SplitPanelCellImage: React.FC<{ value: string }> = React.memo(({ value }) => {
  const [imgSrc, setImgSrc] = React.useState<string | null>(null);
  const [error, setError] = React.useState(false);
  const [loading, setLoading] = React.useState(true);

  React.useEffect(() => {
    let mounted = true;
    const rawValue = String(value);
    const strValue = rawValue.includes(",") ? rawValue.split(",")[0].trim() : rawValue;
    const isObjid = /^\d+$/.test(strValue);

    if (isObjid) {
      const loadImage = async () => {
        try {
          const response = await apiClient.get(`/files/preview/${strValue}`, { responseType: "blob" });
          if (mounted) {
            const blob = new Blob([response.data]);
            setImgSrc(window.URL.createObjectURL(blob));
            setLoading(false);
          }
        } catch {
          if (mounted) { setError(true); setLoading(false); }
        }
      };
      loadImage();
    } else {
      setImgSrc(getFullImageUrl(strValue));
      setLoading(false);
    }

    return () => { mounted = false; };
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [value]);

  if (loading) {
    return (
      <div className="flex items-center justify-center" style={{ minHeight: "32px" }}>
        <div className="h-8 w-8 animate-pulse rounded bg-muted sm:h-10 sm:w-10" />
      </div>
    );
  }

  if (error || !imgSrc) {
    return (
      <div className="flex items-center justify-center" style={{ minHeight: "32px" }}>
        <div className="bg-muted text-muted-foreground flex h-8 w-8 items-center justify-center rounded sm:h-10 sm:w-10" title="이미지를 불러올 수 없습니다">
          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="2" y1="2" x2="22" y2="22"/><path d="M10.41 10.41a2 2 0 1 1-2.83-2.83"/><line x1="13.5" y1="13.5" x2="6" y2="21"/><line x1="18" y1="12" x2="21" y2="15"/><path d="M3.59 3.59A1.99 1.99 0 0 0 3 5v14a2 2 0 0 0 2 2h14c.55 0 1.052-.22 1.41-.59"/><path d="M21 15V5a2 2 0 0 0-2-2H9"/></svg>
        </div>
      </div>
    );
  }

  return (
    <div className="flex items-center justify-center" style={{ minHeight: "32px" }}>
      <img
        src={imgSrc}
        alt="이미지"
        className="h-8 w-8 cursor-pointer rounded object-cover transition-opacity hover:opacity-80 sm:h-10 sm:w-10"
        style={{ maxWidth: "40px", maxHeight: "40px" }}
        onClick={(e) => {
          e.stopPropagation();
          const rawValue = String(value);
          const strValue = rawValue.includes(",") ? rawValue.split(",")[0].trim() : rawValue;
          const isObjid = /^\d+$/.test(strValue);
          window.open(isObjid ? getFilePreviewUrl(strValue) : getFullImageUrl(strValue), "_blank");
        }}
        onError={() => setError(true)}
      />
    </div>
  );
});
SplitPanelCellImage.displayName = "SplitPanelCellImage";

export interface SplitPanelLayoutComponentProps extends ComponentRendererProps {
  // 추가 props
}

/**
 * SplitPanelLayout 컴포넌트
 * 마스터-디테일 패턴의 좌우 분할 레이아웃
 */
export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps> = ({
  component,
  isDesignMode = false,
  isSelected = false,
  isPreview = false,
  onClick,
  ...props
}) => {
  const componentConfig = (component.componentConfig || {}) as SplitPanelLayoutConfig;
  // 🆕 프리뷰용 회사 코드 오버라이드 (최고 관리자만 사용 가능)
  const companyCode = (props as any).companyCode as string | undefined;

  // 기본 설정값
  const splitRatio = componentConfig.splitRatio || 30;
  const resizable = componentConfig.resizable ?? true;
  const minLeftWidth = componentConfig.minLeftWidth || 200;
  const minRightWidth = componentConfig.minRightWidth || 300;

  // 필드 표시 유틸리티 (하드코딩 제거, 동적으로 작동)
  const shouldShowField = (fieldName: string): boolean => {
    const lower = fieldName.toLowerCase();

    // 기본 제외: id, 비밀번호, 토큰, 회사코드
    if (lower === "id" || lower === "company_code" || lower === "company_name") return false;
    if (lower.includes("password") || lower.includes("token")) return false;

    // 나머지는 모두 표시!
    return true;
  };

  // 🆕 엔티티 조인 컬럼명 변환 헬퍼
  // "테이블명.컬럼명" 형식을 "원본컬럼_조인컬럼명" 형식으로 변환하여 데이터 접근
  const getEntityJoinValue = useCallback(
    (item: any, columnName: string, entityColumnMap?: Record<string, string>): any => {
      // 🆕 백엔드가 제공하는 _label 필드 우선 사용
      // 백엔드는 "표시 컬럼"이 설정된 경우 columnName_label을 자동 생성
      const labelKey = `${columnName}_label`;
      if (item[labelKey] !== undefined && item[labelKey] !== "" && item[labelKey] !== null) {
        return item[labelKey];
      }

      // 직접 매칭 시도 (JOIN된 값이 없으면 원본 값 반환)
      if (item[columnName] !== undefined) {
        return item[columnName];
      }

      // "테이블명.컬럼명" 형식인 경우 (예: item_info.item_name)
      if (columnName.includes(".")) {
        const [tableName, fieldName] = columnName.split(".");

        // 🔍 엔티티 조인 컬럼 값 추출
        // 예: item_info.item_name, item_info.standard, item_info.unit

        // 1️⃣ 소스 컬럼 추론 (item_info → item_code, warehouse_info → warehouse_id 등)
        const inferredSourceColumn = tableName.replace("_info", "_code").replace("_mng", "_id");

        // 2️⃣ 정확한 키 매핑 시도: 소스컬럼_필드명
        // 예: item_code_item_name, item_code_standard, item_code_unit
        const exactKey = `${inferredSourceColumn}_${fieldName}`;
        if (item[exactKey] !== undefined) {
          return item[exactKey];
        }

        // 🆕 2-1️⃣ item_id 패턴 시도 (백엔드가 item_id_xxx 형식으로 반환하는 경우)
        // 예: item_info.item_name → item_id_item_name
        const idPatternKey = `${tableName.replace("_info", "_id").replace("_mng", "_id")}_${fieldName}`;
        if (item[idPatternKey] !== undefined) {
          return item[idPatternKey];
        }

        // 3️⃣ 별칭 패턴: 소스컬럼_name (기본 표시 컬럼용)
        // 예: item_code_name (item_name의 별칭)
        if (fieldName === "item_name" || fieldName === "name") {
          const aliasKey = `${inferredSourceColumn}_name`;
          if (item[aliasKey] !== undefined) {
            return item[aliasKey];
          }
          // 🆕 item_id_name 패턴도 시도
          const idAliasKey = `${tableName.replace("_info", "_id").replace("_mng", "_id")}_name`;
          if (item[idAliasKey] !== undefined) {
            return item[idAliasKey];
          }
        }

        // 4️⃣ entityColumnMap에서 매핑 찾기 (화면 설정에서 지정된 경우)
        if (entityColumnMap && entityColumnMap[tableName]) {
          const sourceColumn = entityColumnMap[tableName];
          const joinedColumnName = `${sourceColumn}_${fieldName}`;
          if (item[joinedColumnName] !== undefined) {
            return item[joinedColumnName];
          }
        }

        // 5️⃣ 테이블명_컬럼명 형식으로 시도
        const underscoreKey = `${tableName}_${fieldName}`;
        if (item[underscoreKey] !== undefined) {
          return item[underscoreKey];
        }
      }

      return undefined;
    },
    [],
  );

  // TableOptions Context
  const { registerTable, unregisterTable } = useTableOptions();
  const [leftFilters, setLeftFilters] = useState<TableFilter[]>([]);
  const [leftGrouping, setLeftGrouping] = useState<string[]>([]);
  const [leftColumnVisibility, setLeftColumnVisibility] = useState<ColumnVisibility[]>([]);
  const [leftColumnOrder, setLeftColumnOrder] = useState<string[]>([]); // 🔧 컬럼 순서
  const [leftGroupSumConfig, setLeftGroupSumConfig] = useState<GroupSumConfig | null>(null); // 🆕 그룹별 합산 설정
  const [rightFilters, setRightFilters] = useState<TableFilter[]>([]);
  const [rightGrouping, setRightGrouping] = useState<string[]>([]);
  const [rightColumnVisibility, setRightColumnVisibility] = useState<ColumnVisibility[]>([]);

  // 데이터 상태
  const [leftData, setLeftData] = useState<any[]>([]);
  const [rightData, setRightData] = useState<any[] | any>(null); // 조인 모드는 배열, 상세 모드는 객체
  const [selectedLeftItem, setSelectedLeftItem] = useState<any>(null);
  const [expandedRightItems, setExpandedRightItems] = useState<Set<string | number>>(new Set()); // 확장된 우측 아이템
  const [leftSearchQuery, setLeftSearchQuery] = useState("");
  const [rightSearchQuery, setRightSearchQuery] = useState("");
  const [isLoadingLeft, setIsLoadingLeft] = useState(false);
  const [isLoadingRight, setIsLoadingRight] = useState(false);

  // 🆕 추가 탭 관련 상태
  const [activeTabIndex, setActiveTabIndex] = useState(0); // 0 = 기본 탭 (우측 패널), 1+ = 추가 탭
  const [tabsData, setTabsData] = useState<Record<number, any[]>>({}); // 탭별 데이터 캐시
  const [tabsLoading, setTabsLoading] = useState<Record<number, boolean>>({}); // 탭별 로딩 상태

  const [rightTableColumns, setRightTableColumns] = useState<any[]>([]); // 우측 테이블 컬럼 정보
  const [expandedItems, setExpandedItems] = useState<Set<any>>(new Set()); // 펼쳐진 항목들
  const [leftColumnLabels, setLeftColumnLabels] = useState<Record<string, string>>({}); // 좌측 컬럼 라벨
  const [rightColumnLabels, setRightColumnLabels] = useState<Record<string, string>>({}); // 우측 컬럼 라벨
  const [columnInputTypes, setColumnInputTypes] = useState<Record<string, string>>({}); // 테이블별 컬럼 inputType
  const [leftCategoryMappings, setLeftCategoryMappings] = useState<
    Record<string, Record<string, { label: string; color?: string }>>
  >({}); // 좌측 카테고리 매핑
  const [rightCategoryMappings, setRightCategoryMappings] = useState<
    Record<string, Record<string, { label: string; color?: string }>>
  >({}); // 우측 카테고리 매핑
  const { toast } = useToast();

  // 추가 모달 상태
  const [showAddModal, setShowAddModal] = useState(false);
  const [addModalPanel, setAddModalPanel] = useState<"left" | "right" | "left-item" | null>(null);
  const [addModalFormData, setAddModalFormData] = useState<Record<string, any>>({});

  // 수정 모달 상태
  const [showEditModal, setShowEditModal] = useState(false);
  const [editModalPanel, setEditModalPanel] = useState<"left" | "right" | null>(null);
  const [editModalItem, setEditModalItem] = useState<any>(null);
  const [editModalFormData, setEditModalFormData] = useState<Record<string, any>>({});

  // 삭제 확인 모달 상태
  const [showDeleteModal, setShowDeleteModal] = useState(false);
  const [deleteModalPanel, setDeleteModalPanel] = useState<"left" | "right" | null>(null);
  const [deleteModalItem, setDeleteModalItem] = useState<any>(null);

  // 리사이저 드래그 상태
  const [isDragging, setIsDragging] = useState(false);
  const [leftWidth, setLeftWidth] = useState(splitRatio);
  const containerRef = React.useRef<HTMLDivElement>(null);

  // 🆕 SplitPanel Resize Context 연동 (버튼 등 외부 컴포넌트와 드래그 리사이즈 상태 공유)
  const splitPanelContext = useSplitPanel();
  const {
    registerSplitPanel: ctxRegisterSplitPanel,
    unregisterSplitPanel: ctxUnregisterSplitPanel,
    updateSplitPanel: ctxUpdateSplitPanel,
  } = splitPanelContext;
  const splitPanelId = `split-panel-${component.id}`;

  // 디버깅: Context 연결 상태 확인
  console.log("🔗 [SplitPanelLayout] Context 연결 상태:", {
    componentId: component.id,
    splitPanelId,
    hasRegisterFunc: typeof ctxRegisterSplitPanel === "function",
    splitPanelsSize: splitPanelContext.splitPanels?.size ?? "없음",
  });

  // Context에 분할 패널 등록 (좌표 정보 포함) - 마운트 시 1회만 실행
  const ctxRegisterRef = useRef(ctxRegisterSplitPanel);
  const ctxUnregisterRef = useRef(ctxUnregisterSplitPanel);
  ctxRegisterRef.current = ctxRegisterSplitPanel;
  ctxUnregisterRef.current = ctxUnregisterSplitPanel;

  useEffect(() => {
    // 컴포넌트의 위치와 크기 정보
    const panelX = component.position?.x || 0;
    const panelY = component.position?.y || 0;
    const panelWidth = component.size?.width || component.style?.width || 800;
    const panelHeight = component.size?.height || component.style?.height || 600;

    const panelInfo = {
      x: panelX,
      y: panelY,
      width: typeof panelWidth === "number" ? panelWidth : parseInt(String(panelWidth)) || 800,
      height: typeof panelHeight === "number" ? panelHeight : parseInt(String(panelHeight)) || 600,
      leftWidthPercent: splitRatio, // 초기값은 splitRatio 사용
      initialLeftWidthPercent: splitRatio,
      isDragging: false,
    };

    console.log("📦 [SplitPanelLayout] Context에 분할 패널 등록:", {
      splitPanelId,
      panelInfo,
    });

    ctxRegisterRef.current(splitPanelId, panelInfo);

    return () => {
      console.log("📦 [SplitPanelLayout] Context에서 분할 패널 해제:", splitPanelId);
      ctxUnregisterRef.current(splitPanelId);
    };
    // 마운트/언마운트 시에만 실행, 위치/크기 변경은 별도 업데이트로 처리
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [splitPanelId]);

  // 위치/크기 변경 시 Context 업데이트 (등록 후)
  const ctxUpdateRef = useRef(ctxUpdateSplitPanel);
  ctxUpdateRef.current = ctxUpdateSplitPanel;

  useEffect(() => {
    const panelX = component.position?.x || 0;
    const panelY = component.position?.y || 0;
    const panelWidth = component.size?.width || component.style?.width || 800;
    const panelHeight = component.size?.height || component.style?.height || 600;

    ctxUpdateRef.current(splitPanelId, {
      x: panelX,
      y: panelY,
      width: typeof panelWidth === "number" ? panelWidth : parseInt(String(panelWidth)) || 800,
      height: typeof panelHeight === "number" ? panelHeight : parseInt(String(panelHeight)) || 600,
    });
  }, [
    splitPanelId,
    component.position?.x,
    component.position?.y,
    component.size?.width,
    component.size?.height,
    component.style?.width,
    component.style?.height,
  ]);

  // leftWidth 변경 시 Context 업데이트
  useEffect(() => {
    ctxUpdateRef.current(splitPanelId, { leftWidthPercent: leftWidth });
  }, [leftWidth, splitPanelId]);

  // 드래그 상태 변경 시 Context 업데이트
  // 이전 드래그 상태를 추적하여 드래그 종료 시점을 감지
  const prevIsDraggingRef = useRef(false);

  useEffect(() => {
    const wasJustDragging = prevIsDraggingRef.current && !isDragging;

    if (isDragging) {
      // 드래그 시작 시: 현재 비율을 초기 비율로 저장
      ctxUpdateRef.current(splitPanelId, {
        isDragging: true,
        initialLeftWidthPercent: leftWidth,
      });
    } else if (wasJustDragging) {
      // 드래그 종료 시: 최종 비율을 초기 비율로 업데이트 (버튼 위치 고정)
      ctxUpdateRef.current(splitPanelId, {
        isDragging: false,
        initialLeftWidthPercent: leftWidth,
      });
      console.log("🛑 [SplitPanelLayout] 드래그 종료 - 버튼 위치 고정:", {
        splitPanelId,
        finalLeftWidthPercent: leftWidth,
      });
    }

    prevIsDraggingRef.current = isDragging;
  }, [isDragging, splitPanelId, leftWidth]);

  // 🆕 그룹별 합산된 데이터 계산
  const summedLeftData = useMemo(() => {
    console.log("🔍 [그룹합산] leftGroupSumConfig:", leftGroupSumConfig);

    // 그룹핑이 비활성화되었거나 그룹 기준 컬럼이 없으면 원본 데이터 반환
    if (!leftGroupSumConfig?.enabled || !leftGroupSumConfig?.groupByColumn) {
      console.log("🔍 [그룹합산] 그룹핑 비활성화 - 원본 데이터 반환");
      return leftData;
    }

    const groupByColumn = leftGroupSumConfig.groupByColumn;
    const groupMap = new Map<string, any>();

    // 조인 컬럼인지 확인하고 실제 키 추론
    const getActualKey = (columnName: string, item: any): string => {
      if (columnName.includes(".")) {
        const [refTable, fieldName] = columnName.split(".");
        const inferredSourceColumn = refTable.replace("_info", "_code").replace("_mng", "_id");
        const exactKey = `${inferredSourceColumn}_${fieldName}`;
        console.log("🔍 [그룹합산] 조인 컬럼 키 변환:", { columnName, exactKey, hasKey: item[exactKey] !== undefined });
        if (item[exactKey] !== undefined) return exactKey;
        if (fieldName === "item_name" || fieldName === "name") {
          const aliasKey = `${inferredSourceColumn}_name`;
          if (item[aliasKey] !== undefined) return aliasKey;
        }
      }
      return columnName;
    };

    // 숫자 타입인지 확인하는 함수
    const isNumericValue = (value: any): boolean => {
      if (value === null || value === undefined || value === "") return false;
      const num = parseFloat(String(value));
      return !isNaN(num) && isFinite(num);
    };

    // 그룹핑 수행
    leftData.forEach((item) => {
      const actualKey = getActualKey(groupByColumn, item);
      const groupValue = String(item[actualKey] || item[groupByColumn] || "");

      // 원본 ID 추출 (id, ID, 또는 첫 번째 값)
      const originalId = item.id || item.ID || Object.values(item)[0];

      if (!groupMap.has(groupValue)) {
        // 첫 번째 항목을 기준으로 초기화 + 원본 ID 배열 + 원본 데이터 배열
        groupMap.set(groupValue, {
          ...item,
          _groupCount: 1,
          _originalIds: [originalId],
          _originalItems: [item], // 🆕 원본 데이터 전체 저장
        });
      } else {
        const existing = groupMap.get(groupValue);
        existing._groupCount += 1;
        existing._originalIds.push(originalId);
        existing._originalItems.push(item); // 🆕 원본 데이터 추가

        // 모든 키에 대해 숫자면 합산
        Object.keys(item).forEach((key) => {
          const value = item[key];
          if (isNumericValue(value) && key !== groupByColumn && !key.endsWith("_id") && !key.includes("code")) {
            const numValue = parseFloat(String(value));
            const existingValue = parseFloat(String(existing[key] || 0));
            existing[key] = existingValue + numValue;
          }
        });

        groupMap.set(groupValue, existing);
      }
    });

    const result = Array.from(groupMap.values());
    console.log("🔗 [분할패널] 그룹별 합산 결과:", {
      원본개수: leftData.length,
      그룹개수: result.length,
      그룹기준: groupByColumn,
    });

    return result;
  }, [leftData, leftGroupSumConfig]);

  // 컴포넌트 스타일
  // height 처리: 이미 px 단위면 그대로, 숫자면 px 추가
  const getHeightValue = () => {
    const height = component.style?.height;
    if (!height) return "600px";
    if (typeof height === "string") return height; // 이미 '540px' 형태
    return `${height}px`; // 숫자면 px 추가
  };

  const componentStyle: React.CSSProperties = isDesignMode
    ? {
        position: "absolute",
        left: `${component.style?.positionX || 0}px`,
        top: `${component.style?.positionY || 0}px`,
        width: "100%",
        height: getHeightValue(),
        zIndex: component.style?.positionZ || 1,
        cursor: "pointer",
        border: isSelected ? "2px solid #3b82f6" : "1px solid #e5e7eb",
      }
    : {
        position: "relative",
        width: "100%",
        height: "100%",
        border: "1px solid #e5e7eb",
      };

  // 계층 구조 빌드 함수 (트리 구조 유지)
  const buildHierarchy = useCallback(
    (items: any[]): any[] => {
      if (!items || items.length === 0) return [];

      const itemAddConfig = componentConfig.leftPanel?.itemAddConfig;
      if (!itemAddConfig) return items.map((item) => ({ ...item, children: [] })); // 계층 설정이 없으면 평면 목록

      const { sourceColumn, parentColumn } = itemAddConfig;
      if (!sourceColumn || !parentColumn) return items.map((item) => ({ ...item, children: [] }));

      // ID를 키로 하는 맵 생성
      const itemMap = new Map<any, any>();
      const rootItems: any[] = [];

      // 모든 항목을 맵에 추가하고 children 배열 초기화
      items.forEach((item) => {
        const id = item[sourceColumn];
        itemMap.set(id, { ...item, children: [], level: 0 });
      });

      // 부모-자식 관계 설정
      items.forEach((item) => {
        const id = item[sourceColumn];
        const parentId = item[parentColumn];
        const currentItem = itemMap.get(id);

        if (!currentItem) return;

        if (!parentId || parentId === null || parentId === "") {
          // 최상위 항목
          rootItems.push(currentItem);
        } else {
          // 부모가 있는 항목
          const parentItem = itemMap.get(parentId);
          if (parentItem) {
            currentItem.level = parentItem.level + 1;
            parentItem.children.push(currentItem);
          } else {
            // 부모를 찾을 수 없으면 최상위로 처리
            rootItems.push(currentItem);
          }
        }
      });

      return rootItems;
    },
    [componentConfig.leftPanel?.itemAddConfig],
  );

  // 🔧 사용자 ID 가져오기
  const { userId: currentUserId } = useAuth();

  // 🔄 필터를 searchValues 형식으로 변환
  const searchValues = useMemo(() => {
    if (!leftFilters || leftFilters.length === 0) return {};

    const values: Record<string, any> = {};
    leftFilters.forEach((filter) => {
      if (filter.value !== undefined && filter.value !== null && filter.value !== "") {
        values[filter.columnName] = {
          value: filter.value,
          operator: filter.operator || "contains",
        };
      }
    });
    return values;
  }, [leftFilters]);

  // 🔄 컬럼 가시성 및 순서 처리
  const visibleLeftColumns = useMemo(() => {
    const displayColumns = componentConfig.leftPanel?.columns || [];

    if (displayColumns.length === 0) return [];

    let columns = displayColumns;

    // columnVisibility가 있으면 가시성 적용
    if (leftColumnVisibility.length > 0) {
      const visibilityMap = new Map(leftColumnVisibility.map((cv) => [cv.columnName, cv.visible]));
      columns = columns.filter((col: any) => {
        const colName = typeof col === "string" ? col : col.name || col.columnName;
        return visibilityMap.get(colName) !== false;
      });
    }

    // 🔧 컬럼 순서 적용
    if (leftColumnOrder.length > 0) {
      const orderMap = new Map(leftColumnOrder.map((name, index) => [name, index]));
      columns = [...columns].sort((a, b) => {
        const aName = typeof a === "string" ? a : a.name || a.columnName;
        const bName = typeof b === "string" ? b : b.name || b.columnName;
        const aIndex = orderMap.get(aName) ?? 999;
        const bIndex = orderMap.get(bName) ?? 999;
        return aIndex - bIndex;
      });
    }

    return columns;
  }, [componentConfig.leftPanel?.columns, leftColumnVisibility, leftColumnOrder]);

  // 🔄 데이터 그룹화
  const groupedLeftData = useMemo(() => {
    if (!leftGrouping || leftGrouping.length === 0 || leftData.length === 0) return [];

    const grouped = new Map<string, any[]>();

    leftData.forEach((item) => {
      // 각 그룹 컬럼의 값을 조합하여 그룹 키 생성
      const groupKey = leftGrouping
        .map((col) => {
          const value = item[col];
          // null/undefined 처리
          return value === null || value === undefined ? "(비어있음)" : String(value);
        })
        .join(" > ");

      if (!grouped.has(groupKey)) {
        grouped.set(groupKey, []);
      }
      grouped.get(groupKey)!.push(item);
    });

    return Array.from(grouped.entries()).map(([key, items]) => ({
      groupKey: key,
      items,
      count: items.length,
    }));
  }, [leftData, leftGrouping]);

  // 날짜 포맷팅 헬퍼 함수
  const formatDateValue = useCallback((value: any, dateFormat: string): string => {
    if (!value) return "-";
    const date = new Date(value);
    if (isNaN(date.getTime())) return String(value);

    if (dateFormat === "relative") {
      // 상대 시간 (예: 3일 전, 2시간 전)
      const now = new Date();
      const diffMs = now.getTime() - date.getTime();
      const diffSec = Math.floor(diffMs / 1000);
      const diffMin = Math.floor(diffSec / 60);
      const diffHour = Math.floor(diffMin / 60);
      const diffDay = Math.floor(diffHour / 24);
      const diffMonth = Math.floor(diffDay / 30);
      const diffYear = Math.floor(diffMonth / 12);

      if (diffYear > 0) return `${diffYear}년 전`;
      if (diffMonth > 0) return `${diffMonth}개월 전`;
      if (diffDay > 0) return `${diffDay}일 전`;
      if (diffHour > 0) return `${diffHour}시간 전`;
      if (diffMin > 0) return `${diffMin}분 전`;
      return "방금 전";
    }

    // 포맷 문자열 치환
    return dateFormat
      .replace("YYYY", String(date.getFullYear()))
      .replace("MM", String(date.getMonth() + 1).padStart(2, "0"))
      .replace("DD", String(date.getDate()).padStart(2, "0"))
      .replace("HH", String(date.getHours()).padStart(2, "0"))
      .replace("mm", String(date.getMinutes()).padStart(2, "0"))
      .replace("ss", String(date.getSeconds()).padStart(2, "0"));
  }, []);

  // 숫자 포맷팅 헬퍼 함수
  const formatNumberValue = useCallback((value: any, format: any): string => {
    if (value === null || value === undefined || value === "") return "-";
    const num = typeof value === "number" ? value : parseFloat(String(value));
    if (isNaN(num)) return String(value);

    const options: Intl.NumberFormatOptions = {
      minimumFractionDigits: format?.decimalPlaces ?? 0,
      maximumFractionDigits: format?.decimalPlaces ?? 10,
      useGrouping: format?.thousandSeparator ?? false,
    };

    let result = num.toLocaleString("ko-KR", options);
    if (format?.prefix) result = format.prefix + result;
    if (format?.suffix) result = result + format.suffix;
    return result;
  }, []);

  // 셀 값 포맷팅 함수 (카테고리 타입 처리 + 날짜/숫자 포맷 + 이미지)
  const formatCellValue = useCallback(
    (
      columnName: string,
      value: any,
      categoryMappings: Record<string, Record<string, { label: string; color?: string }>>,
      format?: {
        type?: "number" | "currency" | "date" | "text";
        thousandSeparator?: boolean;
        decimalPlaces?: number;
        prefix?: string;
        suffix?: string;
        dateFormat?: string;
      },
    ) => {
      if (value === null || value === undefined) return "-";

      // 이미지 타입: 썸네일 표시
      const colInputType = columnInputTypes[columnName];
      if (colInputType === "image" && value) {
        return <SplitPanelCellImage value={String(value)} />;
      }

      // 🆕 날짜 포맷 적용
      if (format?.type === "date" || format?.dateFormat) {
        return formatDateValue(value, format?.dateFormat || "YYYY-MM-DD");
      }

      // 🆕 숫자 포맷 적용
      if (
        format?.type === "number" ||
        format?.type === "currency" ||
        format?.thousandSeparator ||
        format?.decimalPlaces !== undefined
      ) {
        return formatNumberValue(value, format);
      }

      // 🆕 카테고리 매핑 찾기 (여러 키 형태 시도)
      // 1. 전체 컬럼명 (예: "item_info.material")
      // 2. 컬럼명만 (예: "material")
      let mapping = categoryMappings[columnName];

      if (!mapping && columnName.includes(".")) {
        // 조인된 컬럼의 경우 컬럼명만으로 다시 시도
        const simpleColumnName = columnName.split(".").pop() || columnName;
        mapping = categoryMappings[simpleColumnName];
      }

      if (mapping && mapping[String(value)]) {
        const categoryData = mapping[String(value)];
        const displayLabel = categoryData.label || String(value);
        const displayColor = categoryData.color || "#64748b";

        // 배지로 표시
        return (
          <Badge
            style={{
              backgroundColor: displayColor,
              borderColor: displayColor,
            }}
            className="text-white"
          >
            {displayLabel}
          </Badge>
        );
      }

      // 🆕 자동 날짜 감지 (ISO 8601 형식 또는 Date 객체)
      if (typeof value === "string" && value.match(/^\d{4}-\d{2}-\d{2}(T|\s)/)) {
        return formatDateValue(value, "YYYY-MM-DD");
      }

      // 🆕 자동 숫자 감지 (숫자 또는 숫자 문자열) - 소수점 있으면 정수로 변환
      if (typeof value === "number") {
        // 숫자인 경우 정수로 표시 (소수점 제거)
        return Number.isInteger(value) ? String(value) : String(Math.round(value * 100) / 100);
      }
      if (typeof value === "string" && /^-?\d+\.?\d*$/.test(value.trim())) {
        // 숫자 문자열인 경우 (예: "5.00" → "5")
        const num = parseFloat(value);
        if (!isNaN(num)) {
          return Number.isInteger(num) ? String(num) : String(Math.round(num * 100) / 100);
        }
      }

      // 일반 값
      return String(value);
    },
    [formatDateValue, formatNumberValue, columnInputTypes],
  );

  // 좌측 데이터 로드
  const loadLeftData = useCallback(async () => {
    const leftTableName = componentConfig.leftPanel?.tableName;
    if (!leftTableName || isDesignMode) return;

    setIsLoadingLeft(true);
    try {
      // 🎯 필터 조건을 API에 전달 (entityJoinApi 사용)
      const filters = Object.keys(searchValues).length > 0 ? searchValues : undefined;

      // 🆕 "테이블명.컬럼명" 형식의 조인 컬럼들을 additionalJoinColumns로 변환
      const configuredColumns = componentConfig.leftPanel?.columns || [];
      const additionalJoinColumns: Array<{
        sourceTable: string;
        sourceColumn: string;
        referenceTable: string;
        joinAlias: string;
      }> = [];

      // 소스 컬럼 매핑 (item_info → item_code, warehouse_info → warehouse_id 등)
      const sourceColumnMap: Record<string, string> = {};

      configuredColumns.forEach((col: any) => {
        const colName = typeof col === "string" ? col : col.name || col.columnName;
        if (colName && colName.includes(".")) {
          const [refTable, refColumn] = colName.split(".");
          // 소스 컬럼 추론 (item_info → item_code 또는 warehouse_info → warehouse_id)
          // 기본: _info → _code, 백업: _info → _id
          const primarySourceColumn = refTable.replace("_info", "_code").replace("_mng", "_id");
          const secondarySourceColumn = refTable.replace("_info", "_id").replace("_mng", "_id");
          // 실제 존재하는 소스 컬럼은 백엔드에서 결정 (프론트엔드는 두 패턴 모두 전달)
          const inferredSourceColumn = primarySourceColumn;

          // 이미 추가된 조인인지 확인 (동일 테이블, 동일 소스컬럼)
          const existingJoin = additionalJoinColumns.find(
            (j) => j.referenceTable === refTable && j.sourceColumn === inferredSourceColumn,
          );

          if (!existingJoin) {
            // 새로운 조인 추가 (첫 번째 컬럼)
            additionalJoinColumns.push({
              sourceTable: leftTableName,
              sourceColumn: inferredSourceColumn,
              referenceTable: refTable,
              joinAlias: `${inferredSourceColumn}_${refColumn}`,
            });
            sourceColumnMap[refTable] = inferredSourceColumn;
          }

          // 추가 컬럼도 별도로 요청 (item_code_standard, item_code_unit 등)
          // 단, 첫 번째 컬럼과 다른 경우만
          const existingAliases = additionalJoinColumns
            .filter((j) => j.referenceTable === refTable)
            .map((j) => j.joinAlias);
          const newAlias = `${sourceColumnMap[refTable] || inferredSourceColumn}_${refColumn}`;

          if (!existingAliases.includes(newAlias)) {
            additionalJoinColumns.push({
              sourceTable: leftTableName,
              sourceColumn: sourceColumnMap[refTable] || inferredSourceColumn,
              referenceTable: refTable,
              joinAlias: newAlias,
            });
          }
        }
      });

      console.log("🔗 [분할패널] additionalJoinColumns:", additionalJoinColumns);
      console.log("🔗 [분할패널] configuredColumns:", configuredColumns);

      const result = await entityJoinApi.getTableDataWithJoins(leftTableName, {
        page: 1,
        size: 100,
        search: filters, // 필터 조건 전달
        enableEntityJoin: true, // 엔티티 조인 활성화
        dataFilter: componentConfig.leftPanel?.dataFilter, // 🆕 데이터 필터 전달
        additionalJoinColumns: additionalJoinColumns.length > 0 ? additionalJoinColumns : undefined, // 🆕 추가 조인 컬럼
        companyCodeOverride: companyCode, // 🆕 프리뷰용 회사 코드 오버라이드
      });

      // 🔍 디버깅: API 응답 데이터의 키 확인
      if (result.data && result.data.length > 0) {
        console.log("🔗 [분할패널] API 응답 첫 번째 데이터 키:", Object.keys(result.data[0]));
        console.log("🔗 [분할패널] API 응답 첫 번째 데이터:", result.data[0]);
      }

      // 가나다순 정렬 (좌측 패널의 표시 컬럼 기준)
      const leftColumn = componentConfig.rightPanel?.relation?.leftColumn;
      if (leftColumn && result.data.length > 0) {
        result.data.sort((a, b) => {
          const aValue = String(a[leftColumn] || "");
          const bValue = String(b[leftColumn] || "");
          return aValue.localeCompare(bValue, "ko-KR");
        });
      }

      // 계층 구조 빌드
      const hierarchicalData = buildHierarchy(result.data);
      setLeftData(hierarchicalData);
    } catch (error) {
      console.error("좌측 데이터 로드 실패:", error);
      toast({
        title: "데이터 로드 실패",
        description: "좌측 패널 데이터를 불러올 수 없습니다.",
        variant: "destructive",
      });
    } finally {
      setIsLoadingLeft(false);
    }
  }, [
    componentConfig.leftPanel?.tableName,
    componentConfig.leftPanel?.columns,
    componentConfig.leftPanel?.dataFilter,
    componentConfig.rightPanel?.relation?.leftColumn,
    isDesignMode,
    toast,
    buildHierarchy,
    searchValues,
  ]);

  // 우측 데이터 로드
  const loadRightData = useCallback(
    async (leftItem: any) => {
      const relationshipType = componentConfig.rightPanel?.relation?.type || "detail";
      const rightTableName = componentConfig.rightPanel?.tableName;

      if (!rightTableName || isDesignMode) return;

      setIsLoadingRight(true);
      try {
        if (relationshipType === "detail") {
          // 상세 모드: 동일 테이블의 상세 정보 (🆕 엔티티 조인 활성화)
          const primaryKey = leftItem.id || leftItem.ID || Object.values(leftItem)[0];

          // 🆕 엔티티 조인 API 사용
          const { entityJoinApi } = await import("@/lib/api/entityJoin");
          const result = await entityJoinApi.getTableDataWithJoins(rightTableName, {
            search: { id: primaryKey },
            enableEntityJoin: true, // 엔티티 조인 활성화
            size: 1,
            companyCodeOverride: companyCode, // 🆕 프리뷰용 회사 코드 오버라이드
          });

          const detail = result.items && result.items.length > 0 ? result.items[0] : null;
          setRightData(detail);
        } else if (relationshipType === "join") {
          // 조인 모드: 다른 테이블의 관련 데이터 (여러 개)
          const keys = componentConfig.rightPanel?.relation?.keys;
          const leftTable = componentConfig.leftPanel?.tableName;

          // 🆕 그룹 합산된 항목인 경우: 원본 데이터들로 우측 패널 표시
          if (leftItem._originalItems && leftItem._originalItems.length > 0) {
            console.log("🔗 [분할패널] 그룹 합산 항목 - 원본 개수:", leftItem._originalItems.length);

            // 정렬 기준 컬럼 (복합키의 leftColumn들)
            const sortColumns = keys?.map((k: any) => k.leftColumn).filter(Boolean) || [];
            console.log("🔗 [분할패널] 정렬 기준 컬럼:", sortColumns);

            // 정렬 함수
            const sortByKeys = (data: any[]) => {
              if (sortColumns.length === 0) return data;
              return [...data].sort((a, b) => {
                for (const col of sortColumns) {
                  const aVal = String(a[col] || "");
                  const bVal = String(b[col] || "");
                  const cmp = aVal.localeCompare(bVal, "ko-KR");
                  if (cmp !== 0) return cmp;
                }
                return 0;
              });
            };

            // 원본 데이터를 그대로 우측 패널에 표시 (이력 테이블과 동일 테이블인 경우)
            if (leftTable === rightTableName) {
              const sortedData = sortByKeys(leftItem._originalItems);
              console.log("🔗 [분할패널] 동일 테이블 - 정렬된 원본 데이터:", sortedData.length);
              setRightData(sortedData);
              return;
            }

            // 다른 테이블인 경우: 원본 ID들로 조회
            const { entityJoinApi } = await import("@/lib/api/entityJoin");
            const allResults: any[] = [];

            // 각 원본 항목에 대해 조회
            for (const originalItem of leftItem._originalItems) {
              const searchConditions: Record<string, any> = {};
              keys?.forEach((key: any) => {
                if (key.leftColumn && key.rightColumn && originalItem[key.leftColumn] !== undefined) {
                  searchConditions[key.rightColumn] = originalItem[key.leftColumn];
                }
              });

              if (Object.keys(searchConditions).length > 0) {
                const result = await entityJoinApi.getTableDataWithJoins(rightTableName, {
                  search: searchConditions,
                  enableEntityJoin: true,
                  size: 1000,
                  companyCodeOverride: companyCode, // 🆕 프리뷰용 회사 코드 오버라이드
                });
                if (result.data) {
                  allResults.push(...result.data);
                }
              }
            }

            // 정렬 적용
            const sortedResults = sortByKeys(allResults);
            console.log("🔗 [분할패널] 그룹 합산 - 우측 패널 정렬된 데이터:", sortedResults.length);
            setRightData(sortedResults);
            return;
          }

          // 🆕 복합키 지원
          if (keys && keys.length > 0 && leftTable) {
            // 복합키: 여러 조건으로 필터링
            const { entityJoinApi } = await import("@/lib/api/entityJoin");

            // 복합키 조건 생성
            // 🔧 entity 타입 컬럼은 코드 값으로 정확히 매칭해야 하므로 operator: 'equals' 사용
            const searchConditions: Record<string, any> = {};
            keys.forEach((key) => {
              if (key.leftColumn && key.rightColumn && leftItem[key.leftColumn] !== undefined) {
                // 연결 필터는 정확한 값 매칭이 필요하므로 equals 연산자 사용
                searchConditions[key.rightColumn] = {
                  value: leftItem[key.leftColumn],
                  operator: "equals",
                };
              }
            });

            console.log("🔗 [분할패널] 복합키 조건:", searchConditions);

            // 엔티티 조인 API로 데이터 조회
            const result = await entityJoinApi.getTableDataWithJoins(rightTableName, {
              search: searchConditions,
              enableEntityJoin: true,
              size: 1000,
              companyCodeOverride: companyCode, // 🆕 프리뷰용 회사 코드 오버라이드
            });

            console.log("🔗 [분할패널] 복합키 조회 결과:", result);

            // 추가 dataFilter 적용
            let filteredData = result.data || [];
            const dataFilter = componentConfig.rightPanel?.dataFilter;
            // 🔧 filters 또는 conditions 배열 모두 지원
            const filterConditions = dataFilter?.filters || dataFilter?.conditions || [];
            if (dataFilter?.enabled && filterConditions.length > 0) {
              console.log(`🔍 [기본탭] dataFilter 설정:`, JSON.stringify(dataFilter, null, 2));
              console.log(`🔍 [기본탭] 필터 전 데이터 수:`, filteredData.length);
              filteredData = filteredData.filter((item: any) => {
                return filterConditions.every((cond: any) => {
                  // 🔧 columnName 또는 column 필드 모두 지원
                  const columnName = cond.columnName || cond.column;
                  const value = item[columnName];
                  const condValue = cond.value;
                  let result = true;
                  switch (cond.operator) {
                    case "equals":
                      result = value === condValue;
                      break;
                    case "notEquals":
                      result = value !== condValue;
                      break;
                    case "contains":
                      result = String(value).includes(String(condValue));
                      break;
                    case "is_null":
                    case "NULL":
                      result = value === null || value === undefined || value === "";
                      break;
                    case "is_not_null":
                    case "NOT NULL":
                      result = value !== null && value !== undefined && value !== "";
                      break;
                    default:
                      result = true;
                  }
                  return result;
                });
              });
              console.log(`🔍 [기본탭] 필터 후 데이터 수:`, filteredData.length);
            }

            setRightData(filteredData);
          } else {
            // 단일키 (하위 호환성)
            const leftColumn = componentConfig.rightPanel?.relation?.leftColumn;
            const rightColumn = componentConfig.rightPanel?.relation?.foreignKey;

            if (leftColumn && rightColumn && leftTable) {
              const leftValue = leftItem[leftColumn];
              const joinedData = await dataApi.getJoinedData(
                leftTable,
                rightTableName,
                leftColumn,
                rightColumn,
                leftValue,
                componentConfig.rightPanel?.dataFilter, // 🆕 데이터 필터 전달
                true, // 🆕 Entity 조인 활성화
                componentConfig.rightPanel?.columns, // 🆕 표시 컬럼 전달 (item_info.item_name 등)
                componentConfig.rightPanel?.deduplication, // 🆕 중복 제거 설정 전달
              );
              setRightData(joinedData || []); // 모든 관련 레코드 (배열)
            }
          }
        }
      } catch (error) {
        console.error("우측 데이터 로드 실패:", error);
        toast({
          title: "데이터 로드 실패",
          description: "우측 패널 데이터를 불러올 수 없습니다.",
          variant: "destructive",
        });
      } finally {
        setIsLoadingRight(false);
      }
    },
    [
      componentConfig.rightPanel?.tableName,
      componentConfig.rightPanel?.relation,
      componentConfig.leftPanel?.tableName,
      isDesignMode,
      toast,
    ],
  );

  // 🆕 추가 탭 데이터 로딩 함수
  const loadTabData = useCallback(
    async (tabIndex: number, leftItem: any) => {
      const tabConfig = componentConfig.rightPanel?.additionalTabs?.[tabIndex - 1];
      if (!tabConfig || !leftItem || isDesignMode) return;

      const tabTableName = tabConfig.tableName;
      if (!tabTableName) return;

      setTabsLoading((prev) => ({ ...prev, [tabIndex]: true }));
      try {
        // 조인 키 확인
        const keys = tabConfig.relation?.keys;
        const leftColumn = tabConfig.relation?.leftColumn || keys?.[0]?.leftColumn;
        const rightColumn = tabConfig.relation?.foreignKey || keys?.[0]?.rightColumn;

        let resultData: any[] = [];

        if (leftColumn && rightColumn) {
          // 조인 조건이 있는 경우
          const { entityJoinApi } = await import("@/lib/api/entityJoin");
          const searchConditions: Record<string, any> = {};

          if (keys && keys.length > 0) {
            // 복합키
            // 🔧 entity 타입 컬럼은 코드 값으로 정확히 매칭해야 하므로 operator: 'equals' 사용
            keys.forEach((key) => {
              if (key.leftColumn && key.rightColumn && leftItem[key.leftColumn] !== undefined) {
                searchConditions[key.rightColumn] = {
                  value: leftItem[key.leftColumn],
                  operator: "equals",
                };
              }
            });
          } else {
            // 단일키
            // 🔧 entity 타입 컬럼은 코드 값으로 정확히 매칭해야 하므로 operator: 'equals' 사용
            const leftValue = leftItem[leftColumn];
            if (leftValue !== undefined) {
              searchConditions[rightColumn] = {
                value: leftValue,
                operator: "equals",
              };
            }
          }

          console.log(`🔗 [추가탭 ${tabIndex}] 조회 조건:`, searchConditions);

          const result = await entityJoinApi.getTableDataWithJoins(tabTableName, {
            search: searchConditions,
            enableEntityJoin: true,
            size: 1000,
          });

          resultData = result.data || [];
        } else {
          // 조인 조건이 없는 경우: 전체 데이터 조회 (독립 탭)
          const { entityJoinApi } = await import("@/lib/api/entityJoin");
          const result = await entityJoinApi.getTableDataWithJoins(tabTableName, {
            enableEntityJoin: true,
            size: 1000,
          });
          resultData = result.data || [];
        }

        // 데이터 필터 적용
        const dataFilter = tabConfig.dataFilter;
        console.log(`🔍 [추가탭 ${tabIndex}] dataFilter 설정:`, JSON.stringify(dataFilter, null, 2));
        // 🔧 filters 또는 conditions 배열 모두 지원 (DataFilterConfigPanel은 filters 사용)
        const filterConditions = dataFilter?.filters || dataFilter?.conditions || [];
        console.log(`🔍 [추가탭 ${tabIndex}] filterConditions:`, filterConditions);
        console.log(`🔍 [추가탭 ${tabIndex}] 필터 전 데이터 수:`, resultData.length);
        if (dataFilter?.enabled && filterConditions.length > 0) {
          const beforeCount = resultData.length;
          resultData = resultData.filter((item: any) => {
            return filterConditions.every((cond: any) => {
              // 🔧 columnName 또는 column 필드 모두 지원
              const columnName = cond.columnName || cond.column;
              const value = item[columnName];
              const condValue = cond.value;
              let result = true;
              switch (cond.operator) {
                case "equals":
                  result = value === condValue;
                  break;
                case "notEquals":
                  result = value !== condValue;
                  break;
                case "contains":
                  result = String(value).includes(String(condValue));
                  break;
                case "is_null":
                case "NULL":
                  result = value === null || value === undefined || value === "";
                  break;
                case "is_not_null":
                case "NOT NULL":
                  result = value !== null && value !== undefined && value !== "";
                  break;
                default:
                  result = true;
              }
              console.log(`🔍 [필터 체크] ${columnName}=${JSON.stringify(value)}, operator=${cond.operator}, result=${result}`);
              return result;
            });
          });
          console.log(`🔍 [추가탭 ${tabIndex}] 필터 후 데이터 수: ${beforeCount} → ${resultData.length}`);
        } else {
          console.log(`🔍 [추가탭 ${tabIndex}] 필터 비활성화 또는 조건 없음 (enabled=${dataFilter?.enabled}, conditions=${filterConditions.length})`);
        }

        // 중복 제거 적용
        const deduplication = tabConfig.deduplication;
        if (deduplication?.enabled && deduplication.groupByColumn) {
          const groupedMap = new Map<string, any>();
          resultData.forEach((item) => {
            const key = String(item[deduplication.groupByColumn] || "");
            const existing = groupedMap.get(key);
            if (!existing) {
              groupedMap.set(key, item);
            } else {
              // keepStrategy에 따라 유지할 항목 결정
              const sortCol = deduplication.sortColumn || "start_date";
              const existingVal = existing[sortCol];
              const newVal = item[sortCol];
              if (deduplication.keepStrategy === "latest" && newVal > existingVal) {
                groupedMap.set(key, item);
              } else if (deduplication.keepStrategy === "earliest" && newVal < existingVal) {
                groupedMap.set(key, item);
              }
            }
          });
          resultData = Array.from(groupedMap.values());
        }

        console.log(`🔗 [추가탭 ${tabIndex}] 결과 데이터:`, resultData.length);
        setTabsData((prev) => ({ ...prev, [tabIndex]: resultData }));
      } catch (error) {
        console.error(`추가탭 ${tabIndex} 데이터 로드 실패:`, error);
        toast({
          title: "데이터 로드 실패",
          description: `탭 데이터를 불러올 수 없습니다.`,
          variant: "destructive",
        });
      } finally {
        setTabsLoading((prev) => ({ ...prev, [tabIndex]: false }));
      }
    },
    [componentConfig.rightPanel?.additionalTabs, isDesignMode, toast],
  );

  // 좌측 항목 선택 핸들러
  const handleLeftItemSelect = useCallback(
    (item: any) => {
      setSelectedLeftItem(item);
      setExpandedRightItems(new Set()); // 좌측 항목 변경 시 우측 확장 초기화
      setTabsData({}); // 🆕 모든 탭 데이터 초기화

      // 🆕 현재 활성 탭에 따라 데이터 로드
      if (activeTabIndex === 0) {
        loadRightData(item);
      } else {
        loadTabData(activeTabIndex, item);
      }

      // 🆕 modalDataStore에 선택된 좌측 항목 저장 (단일 선택)
      const leftTableName = componentConfig.leftPanel?.tableName;
      if (leftTableName && !isDesignMode) {
        import("@/stores/modalDataStore").then(({ useModalDataStore }) => {
          useModalDataStore.getState().setData(leftTableName, [item]);
          console.log(`✅ 분할 패널 좌측 선택: ${leftTableName}`, item);
        });
      }
    },
    [loadRightData, loadTabData, activeTabIndex, componentConfig.leftPanel?.tableName, isDesignMode],
  );

  // 🆕 탭 변경 핸들러
  const handleTabChange = useCallback(
    (newTabIndex: number) => {
      setActiveTabIndex(newTabIndex);

      // 선택된 좌측 항목이 있으면 해당 탭의 데이터 로드
      if (selectedLeftItem) {
        if (newTabIndex === 0) {
          // 기본 탭: 우측 패널 데이터가 없으면 로드
          if (!rightData || (Array.isArray(rightData) && rightData.length === 0)) {
            loadRightData(selectedLeftItem);
          }
        } else {
          // 추가 탭: 해당 탭 데이터가 없으면 로드
          if (!tabsData[newTabIndex]) {
            loadTabData(newTabIndex, selectedLeftItem);
          }
        }
      }
    },
    [selectedLeftItem, rightData, tabsData, loadRightData, loadTabData],
  );

  // 우측 항목 확장/축소 토글
  const toggleRightItemExpansion = useCallback((itemId: string | number) => {
    setExpandedRightItems((prev) => {
      const newSet = new Set(prev);
      if (newSet.has(itemId)) {
        newSet.delete(itemId);
      } else {
        newSet.add(itemId);
      }
      return newSet;
    });
  }, []);

  // 컬럼명을 라벨로 변환하는 함수
  const getColumnLabel = useCallback(
    (columnName: string) => {
      const column = rightTableColumns.find((col) => col.columnName === columnName || col.column_name === columnName);
      return column?.columnLabel || column?.column_label || column?.displayName || columnName;
    },
    [rightTableColumns],
  );

  // 🔧 컬럼의 고유값 가져오기 함수
  const getLeftColumnUniqueValues = useCallback(
    async (columnName: string) => {
      const leftTableName = componentConfig.leftPanel?.tableName;
      if (!leftTableName) return [];

      // 1단계: 카테고리 API 시도 (DB에서 라벨 조회)
      try {
        const { apiClient } = await import("@/lib/api/client");
        const response = await apiClient.get(`/table-categories/${leftTableName}/${columnName}/values`);
        if (response.data.success && response.data.data && response.data.data.length > 0) {
          return response.data.data.map((item: any) => ({
            value: item.valueCode,
            label: item.valueLabel,
          }));
        }
      } catch {
        // 카테고리 API 실패 시 다음 단계로
      }

      // 2단계: DISTINCT API (백엔드 라벨 변환 포함)
      try {
        const { apiClient } = await import("@/lib/api/client");
        const response = await apiClient.get(`/entity/${leftTableName}/distinct/${columnName}`);
        if (response.data.success && response.data.data && response.data.data.length > 0) {
          return response.data.data.map((item: any) => ({
            value: String(item.value),
            label: String(item.label),
          }));
        }
      } catch {
        // DISTINCT API 실패 시 다음 단계로
      }

      // 3단계: 로컬 데이터에서 고유값 추출 (최종 fallback)
      if (leftData.length === 0) return [];

      const uniqueValuesMap = new Map<string, string>();

      leftData.forEach((item) => {
        let value: any;

        if (columnName.includes(".")) {
          const [refTable, fieldName] = columnName.split(".");
          const inferredSourceColumn = refTable.replace("_info", "_code").replace("_mng", "_id");

          const exactKey = `${inferredSourceColumn}_${fieldName}`;
          value = item[exactKey];

          if (value === undefined) {
            const idPatternKey = `${refTable.replace("_info", "_id").replace("_mng", "_id")}_${fieldName}`;
            value = item[idPatternKey];
          }

          if (value === undefined && (fieldName === "item_name" || fieldName === "name")) {
            const aliasKey = `${inferredSourceColumn}_name`;
            value = item[aliasKey];
            if (value === undefined) {
              const idAliasKey = `${refTable.replace("_info", "_id").replace("_mng", "_id")}_name`;
              value = item[idAliasKey];
            }
          }
        } else {
          value = item[columnName];
        }

        if (value !== null && value !== undefined && value !== "") {
          const strValue = String(value);
          const nameField = item[`${columnName}_name`];
          const label = nameField || strValue;
          uniqueValuesMap.set(strValue, label);
        }
      });

      return Array.from(uniqueValuesMap.entries())
        .map(([value, label]) => ({ value, label }))
        .sort((a, b) => a.label.localeCompare(b.label));
    },
    [componentConfig.leftPanel?.tableName, leftData],
  );

  // 좌측 테이블 등록 (Context에 등록)
  useEffect(() => {
    const leftTableName = componentConfig.leftPanel?.tableName;
    if (!leftTableName || isDesignMode) return;

    const leftTableId = `split-panel-left-${component.id}`;
    // 🔧 화면에 표시되는 컬럼 사용 (columns 속성)
    const configuredColumns = componentConfig.leftPanel?.columns || [];

    // 🆕 설정에서 지정한 라벨 맵 생성
    const configuredLabels: Record<string, string> = {};
    configuredColumns.forEach((col: any) => {
      if (typeof col === "object" && col.name && col.label) {
        configuredLabels[col.name] = col.label;
      }
    });

    const displayColumns = configuredColumns
      .map((col: any) => {
        if (typeof col === "string") return col;
        return col.columnName || col.name || col;
      })
      .filter(Boolean);

    // 화면에 설정된 컬럼이 없으면 등록하지 않음
    if (displayColumns.length === 0) return;

    // 테이블명이 있으면 등록
    registerTable({
      tableId: leftTableId,
      label: `${component.title || "분할 패널"} (좌측)`,
      tableName: leftTableName,
      columns: displayColumns.map((col: string) => ({
        columnName: col,
        // 🆕 우선순위: 1) 설정에서 지정한 라벨 2) DB 라벨 3) 컬럼명
        columnLabel: configuredLabels[col] || leftColumnLabels[col] || col,
        inputType: "text",
        visible: true,
        width: 150,
        sortable: true,
        filterable: true,
      })),
      onFilterChange: setLeftFilters,
      onGroupChange: setLeftGrouping,
      onColumnVisibilityChange: setLeftColumnVisibility,
      onColumnOrderChange: setLeftColumnOrder, // 🔧 컬럼 순서 변경 콜백 추가
      getColumnUniqueValues: getLeftColumnUniqueValues, // 🔧 고유값 가져오기 함수 추가
      onGroupSumChange: setLeftGroupSumConfig, // 🆕 그룹별 합산 설정 콜백
    });

    return () => unregisterTable(leftTableId);
  }, [
    component.id,
    componentConfig.leftPanel?.tableName,
    componentConfig.leftPanel?.columns,
    leftColumnLabels,
    component.title,
    isDesignMode,
    getLeftColumnUniqueValues,
  ]);

  // 우측 테이블은 검색 컴포넌트 등록 제외 (좌측 마스터 테이블만 검색 가능)
  // useEffect(() => {
  //   const rightTableName = componentConfig.rightPanel?.tableName;
  //   if (!rightTableName || isDesignMode) return;
  //
  //   const rightTableId = `split-panel-right-${component.id}`;
  //   // 🔧 화면에 표시되는 컬럼만 등록 (displayColumns 또는 columns)
  //   const displayColumns = componentConfig.rightPanel?.columns || [];
  //   const rightColumns = displayColumns.map((col: any) => col.columnName || col.name || col).filter(Boolean);
  //
  //   if (rightColumns.length > 0) {
  //     registerTable({
  //       tableId: rightTableId,
  //       label: `${component.title || "분할 패널"} (우측)`,
  //       tableName: rightTableName,
  //       columns: rightColumns.map((col: string) => ({
  //         columnName: col,
  //         columnLabel: rightColumnLabels[col] || col,
  //         inputType: "text",
  //         visible: true,
  //         width: 150,
  //         sortable: true,
  //         filterable: true,
  //       })),
  //       onFilterChange: setRightFilters,
  //       onGroupChange: setRightGrouping,
  //       onColumnVisibilityChange: setRightColumnVisibility,
  //     });
  //
  //     return () => unregisterTable(rightTableId);
  //   }
  // }, [component.id, componentConfig.rightPanel?.tableName, componentConfig.rightPanel?.columns, rightColumnLabels, component.title, isDesignMode]);

  // 좌측 테이블 컬럼 라벨 로드
  useEffect(() => {
    const loadLeftColumnLabels = async () => {
      const leftTableName = componentConfig.leftPanel?.tableName;
      if (!leftTableName || isDesignMode) return;

      try {
        const columnsResponse = await tableTypeApi.getColumns(leftTableName);
        const labels: Record<string, string> = {};
        columnsResponse.forEach((col: any) => {
          const columnName = col.columnName || col.column_name;
          const label = col.columnLabel || col.column_label || col.displayName || columnName;
          if (columnName) {
            labels[columnName] = label;
          }
        });
        setLeftColumnLabels(labels);
        console.log("✅ 좌측 컬럼 라벨 로드:", labels);
      } catch (error) {
        console.error("좌측 테이블 컬럼 라벨 로드 실패:", error);
      }
    };

    loadLeftColumnLabels();
  }, [componentConfig.leftPanel?.tableName, isDesignMode]);

  // 우측 테이블 컬럼 정보 로드
  useEffect(() => {
    const loadRightTableColumns = async () => {
      const rightTableName = componentConfig.rightPanel?.tableName;
      if (!rightTableName || isDesignMode) return;

      try {
        const columnsResponse = await tableTypeApi.getColumns(rightTableName);
        setRightTableColumns(columnsResponse || []);

        // 우측 컬럼 라벨도 함께 로드
        const labels: Record<string, string> = {};
        columnsResponse.forEach((col: any) => {
          const columnName = col.columnName || col.column_name;
          const label = col.columnLabel || col.column_label || col.displayName || columnName;
          if (columnName) {
            labels[columnName] = label;
          }
        });
        setRightColumnLabels(labels);

        // 우측 테이블 + 추가 탭 테이블의 inputType 로드
        const tablesToLoad = new Set<string>([rightTableName]);
        const additionalTabs = componentConfig.rightPanel?.additionalTabs || [];
        additionalTabs.forEach((tab: any) => {
          if (tab.tableName) tablesToLoad.add(tab.tableName);
        });

        const inputTypes: Record<string, string> = {};
        for (const tbl of tablesToLoad) {
          try {
            const inputTypesResponse = await tableTypeApi.getColumnInputTypes(tbl);
            inputTypesResponse.forEach((col: any) => {
              const colName = col.columnName || col.column_name;
              if (colName) {
                inputTypes[colName] = col.inputType || "text";
              }
            });
          } catch {
            // inputType 로드 실패 시 무시
          }
        }
        setColumnInputTypes(inputTypes);
      } catch (error) {
        console.error("우측 테이블 컬럼 정보 로드 실패:", error);
      }
    };

    loadRightTableColumns();
  }, [componentConfig.rightPanel?.tableName, componentConfig.rightPanel?.additionalTabs, isDesignMode]);

  // 좌측 테이블 카테고리 매핑 로드
  useEffect(() => {
    const loadLeftCategoryMappings = async () => {
      const leftTableName = componentConfig.leftPanel?.tableName;
      if (!leftTableName || isDesignMode) return;

      try {
        // 1. 컬럼 메타 정보 조회
        const columnsResponse = await tableTypeApi.getColumns(leftTableName);
        const categoryColumns = columnsResponse.filter((col: any) => col.inputType === "category");

        if (categoryColumns.length === 0) {
          setLeftCategoryMappings({});
          return;
        }

        // 2. 각 카테고리 컬럼에 대한 값 조회
        const mappings: Record<string, Record<string, { label: string; color?: string }>> = {};

        for (const col of categoryColumns) {
          const columnName = col.columnName || col.column_name;
          try {
            const response = await apiClient.get(`/table-categories/${leftTableName}/${columnName}/values?includeInactive=true`);

            if (response.data.success && response.data.data) {
              const valueMap: Record<string, { label: string; color?: string }> = {};
              response.data.data.forEach((item: any) => {
                valueMap[item.value_code || item.valueCode] = {
                  label: item.value_label || item.valueLabel,
                  color: item.color,
                };
              });
              mappings[columnName] = valueMap;
              console.log(`✅ 좌측 카테고리 매핑 로드 [${columnName}]:`, valueMap);
            }
          } catch (error) {
            console.error(`좌측 카테고리 값 조회 실패 [${columnName}]:`, error);
          }
        }

        setLeftCategoryMappings(mappings);
      } catch (error) {
        console.error("좌측 카테고리 매핑 로드 실패:", error);
      }
    };

    loadLeftCategoryMappings();
  }, [componentConfig.leftPanel?.tableName, isDesignMode]);

  // 우측 테이블 카테고리 매핑 로드 (조인된 테이블 포함)
  useEffect(() => {
    const loadRightCategoryMappings = async () => {
      const rightTableName = componentConfig.rightPanel?.tableName;
      if (!rightTableName || isDesignMode) return;

      try {
        const mappings: Record<string, Record<string, { label: string; color?: string }>> = {};

        // 🆕 우측 패널 컬럼 설정에서 조인된 테이블 추출
        const rightColumns = componentConfig.rightPanel?.columns || [];
        const tablesToLoad = new Set<string>([rightTableName]);

        // 컬럼명에서 테이블명 추출 (예: "item_info.material" -> "item_info")
        rightColumns.forEach((col: any) => {
          const colName = col.name || col.columnName;
          if (colName && colName.includes(".")) {
            const joinTableName = colName.split(".")[0];
            tablesToLoad.add(joinTableName);
          }
        });

        console.log("🔍 우측 패널 카테고리 로드 대상 테이블:", Array.from(tablesToLoad));

        // 각 테이블에 대해 카테고리 매핑 로드
        for (const tableName of tablesToLoad) {
          try {
            // 1. 컬럼 메타 정보 조회
            const columnsResponse = await tableTypeApi.getColumns(tableName);
            const categoryColumns = columnsResponse.filter((col: any) => col.inputType === "category");

            // 2. 각 카테고리 컬럼에 대한 값 조회
            for (const col of categoryColumns) {
              const columnName = col.columnName || col.column_name;
              try {
                const response = await apiClient.get(`/table-categories/${tableName}/${columnName}/values?includeInactive=true`);

                if (response.data.success && response.data.data) {
                  const valueMap: Record<string, { label: string; color?: string }> = {};
                  response.data.data.forEach((item: any) => {
                    valueMap[item.value_code || item.valueCode] = {
                      label: item.value_label || item.valueLabel,
                      color: item.color,
                    };
                  });

                  // 조인된 테이블의 경우 "테이블명.컬럼명" 형태로 저장
                  const mappingKey = tableName === rightTableName ? columnName : `${tableName}.${columnName}`;
                  mappings[mappingKey] = valueMap;

                  // 🆕 컬럼명만으로도 접근할 수 있도록 추가 저장 (모든 테이블)
                  // 기존 매핑이 있으면 병합, 없으면 새로 생성
                  mappings[columnName] = { ...(mappings[columnName] || {}), ...valueMap };

                  console.log(`✅ 우측 카테고리 매핑 로드 [${mappingKey}]:`, valueMap);
                  console.log(`✅ 우측 카테고리 매핑 (컬럼명만) [${columnName}]:`, mappings[columnName]);
                }
              } catch (error) {
                console.error(`우측 카테고리 값 조회 실패 [${tableName}.${columnName}]:`, error);
              }
            }
          } catch (error) {
            console.error(`테이블 ${tableName} 컬럼 정보 조회 실패:`, error);
          }
        }

        setRightCategoryMappings(mappings);
      } catch (error) {
        console.error("우측 카테고리 매핑 로드 실패:", error);
      }
    };

    loadRightCategoryMappings();
  }, [componentConfig.rightPanel?.tableName, componentConfig.rightPanel?.columns, isDesignMode]);

  // 항목 펼치기/접기 토글
  const toggleExpand = useCallback((itemId: any) => {
    setExpandedItems((prev) => {
      const newSet = new Set(prev);
      if (newSet.has(itemId)) {
        newSet.delete(itemId);
      } else {
        newSet.add(itemId);
      }
      return newSet;
    });
  }, []);

  // 추가 버튼 핸들러
  const handleAddClick = useCallback(
    (panel: "left" | "right") => {
      console.log("🆕 [추가모달] handleAddClick 호출:", { panel, activeTabIndex });

      // screenId 기반 모달 확인
      const panelConfig = panel === "left" ? componentConfig.leftPanel : componentConfig.rightPanel;
      const addModalConfig = panelConfig?.addModal;

      if (addModalConfig?.screenId) {
        if (panel === "right" && !selectedLeftItem) {
          toast({
            title: "항목을 선택해주세요",
            description: "좌측 패널에서 항목을 먼저 선택한 후 추가해주세요.",
            variant: "destructive",
          });
          return;
        }

        const tableName = panelConfig?.tableName || "";
        const urlParams: Record<string, any> = {
          mode: "add",
          tableName,
        };

        const parentData: Record<string, any> = {};
        if (panel === "right" && selectedLeftItem) {
          const relation = componentConfig.rightPanel?.relation;
          console.log("🟢 [추가모달] selectedLeftItem:", JSON.stringify(selectedLeftItem));
          console.log("🟢 [추가모달] relation:", JSON.stringify(relation));
          if (relation?.keys && Array.isArray(relation.keys)) {
            for (const key of relation.keys) {
              console.log("🟢 [추가모달] key:", key, "leftValue:", selectedLeftItem[key.leftColumn]);
              if (key.leftColumn && key.rightColumn && selectedLeftItem[key.leftColumn] != null) {
                parentData[key.rightColumn] = selectedLeftItem[key.leftColumn];
              }
            }
          }
        }

        console.log("🆕 [추가모달] screenId 기반 모달 열기:", { screenId: addModalConfig.screenId, tableName, parentData, parentDataStr: JSON.stringify(parentData) });

        window.dispatchEvent(
          new CustomEvent("openScreenModal", {
            detail: {
              screenId: addModalConfig.screenId,
              urlParams,
              splitPanelParentData: parentData,
            },
          }),
        );
        return;
      }

      // 기존 인라인 모달 방식
      setAddModalPanel(panel);

      // 우측 패널 추가 시, 좌측에서 선택된 항목의 조인 컬럼 값을 자동으로 채움
      if (
        panel === "right" &&
        selectedLeftItem &&
        componentConfig.leftPanel?.leftColumn &&
        componentConfig.rightPanel?.rightColumn
      ) {
        const leftColumnValue = selectedLeftItem[componentConfig.leftPanel.leftColumn];
        const initialData = {
          [componentConfig.rightPanel.rightColumn]: leftColumnValue,
        };
        console.log("🆕 [추가모달] 초기 데이터 설정:", initialData);
        setAddModalFormData(initialData);
      } else {
        console.log("🆕 [추가모달] 빈 데이터로 초기화");
        setAddModalFormData({});
      }

      setShowAddModal(true);
    },
    [selectedLeftItem, componentConfig, activeTabIndex],
  );

  // 수정 버튼 핸들러
  const handleEditClick = useCallback(
    (panel: "left" | "right", item: any) => {
      // 🆕 우측 패널 수정 버튼 설정 확인
      // 🔧 현재 활성 탭에 따라 해당 탭의 editButton 설정 사용
      if (panel === "right") {
        // 기본 탭(0)이면 rightPanel.editButton, 추가 탭이면 additionalTabs의 editButton 사용
        const editButtonConfig =
          activeTabIndex === 0
            ? componentConfig.rightPanel?.editButton
            : componentConfig.rightPanel?.additionalTabs?.[activeTabIndex - 1]?.editButton;

        // 해당 탭의 테이블명 가져오기
        const currentTableName =
          activeTabIndex === 0
            ? componentConfig.rightPanel?.tableName || ""
            : componentConfig.rightPanel?.additionalTabs?.[activeTabIndex - 1]?.tableName || "";

        console.log("🔧 [SplitPanel] 수정 버튼 클릭 - 현재 탭 설정 확인:", {
          activeTabIndex,
          editButtonConfig,
          currentTableName,
          isModalMode: editButtonConfig?.mode === "modal",
        });

        if (editButtonConfig?.mode === "modal") {
          const modalScreenId = editButtonConfig.modalScreenId;

          if (modalScreenId) {
            // 커스텀 모달 화면 열기

            // Primary Key 찾기 (우선순위: 설정값 > id > ID > non-null 필드)
            // 🔧 설정에서 primaryKeyColumn 지정 가능
            const configuredPrimaryKey = editButtonConfig.primaryKeyColumn;

            let primaryKeyName = "id";
            let primaryKeyValue: any;

            if (configuredPrimaryKey && item[configuredPrimaryKey] !== undefined && item[configuredPrimaryKey] !== null) {
              // 설정된 Primary Key 사용
              primaryKeyName = configuredPrimaryKey;
              primaryKeyValue = item[configuredPrimaryKey];
            } else if (item.id !== undefined && item.id !== null) {
              primaryKeyName = "id";
              primaryKeyValue = item.id;
            } else if (item.ID !== undefined && item.ID !== null) {
              primaryKeyName = "ID";
              primaryKeyValue = item.ID;
            } else {
              // 🔧 첫 번째 non-null 필드를 Primary Key로 간주
              const keys = Object.keys(item);
              let found = false;
              for (const key of keys) {
                if (item[key] !== undefined && item[key] !== null) {
                  primaryKeyName = key;
                  primaryKeyValue = item[key];
                  found = true;
                  break;
                }
              }
              // 모든 필드가 null이면 첫 번째 필드 사용
              if (!found && keys.length > 0) {
                primaryKeyName = keys[0];
                primaryKeyValue = item[keys[0]];
              }
            }

            console.log("✅ 수정 모달 열기:", {
              activeTabIndex,
              tableName: currentTableName,
              primaryKeyName,
              primaryKeyValue,
              screenId: modalScreenId,
              fullItem: item,
            });

            // modalDataStore에도 저장 (호환성 유지)
            import("@/stores/modalDataStore").then(({ useModalDataStore }) => {
              useModalDataStore.getState().setData(currentTableName, [item]);
            });

            // 🆕 groupByColumns 추출
            const groupByColumns = editButtonConfig.groupByColumns || [];

            console.log("🔧 [SplitPanel] 수정 버튼 클릭 - groupByColumns 확인:", {
              groupByColumns,
              editButtonConfig,
              hasGroupByColumns: groupByColumns.length > 0,
            });

            // ScreenModal 열기 이벤트 발생 (URL 파라미터로 ID + groupByColumns + primaryKeyColumn 전달)
            window.dispatchEvent(
              new CustomEvent("openScreenModal", {
                detail: {
                  screenId: modalScreenId,
                  urlParams: {
                    mode: "edit",
                    editId: primaryKeyValue,
                    tableName: currentTableName,
                    primaryKeyColumn: primaryKeyName, // 🆕 Primary Key 컬럼명 전달
                    ...(groupByColumns.length > 0 && {
                      groupByColumns: JSON.stringify(groupByColumns),
                    }),
                  },
                },
              }),
            );

            console.log("✅ [SplitPanel] openScreenModal 이벤트 발생:", {
              screenId: modalScreenId,
              editId: primaryKeyValue,
              tableName: currentTableName,
              primaryKeyColumn: primaryKeyName,
              groupByColumns: groupByColumns.length > 0 ? JSON.stringify(groupByColumns) : "없음",
            });

            return;
          }
        }
      }

      // 기존 자동 편집 모드 (인라인 편집 모달)
      setEditModalPanel(panel);
      setEditModalItem(item);

      // 🔧 우측 패널(추가탭 포함) 수정 시 selectedLeftItem의 FK 값 병합
      let mergedItem = { ...item };
      if (panel === "right" && selectedLeftItem) {
        // 현재 활성 탭의 relation 설정 가져오기
        const currentTabConfig =
          activeTabIndex === 0
            ? componentConfig.rightPanel
            : componentConfig.rightPanel?.additionalTabs?.[activeTabIndex - 1];

        const relationKeys = currentTabConfig?.relation?.keys;
        const leftColumn = currentTabConfig?.relation?.leftColumn;
        const rightColumn = currentTabConfig?.relation?.foreignKey || currentTabConfig?.relation?.rightColumn;

        if (relationKeys && relationKeys.length > 0) {
          // 복합키인 경우
          relationKeys.forEach((key: any) => {
            if (key.leftColumn && key.rightColumn && selectedLeftItem[key.leftColumn] !== undefined) {
              // item에 해당 FK 값이 없거나 빈 값이면 selectedLeftItem에서 가져옴
              if (mergedItem[key.rightColumn] === undefined || mergedItem[key.rightColumn] === null || mergedItem[key.rightColumn] === "") {
                mergedItem[key.rightColumn] = selectedLeftItem[key.leftColumn];
              }
            }
          });
        } else if (leftColumn && rightColumn) {
          // 단일키인 경우
          if (selectedLeftItem[leftColumn] !== undefined) {
            if (mergedItem[rightColumn] === undefined || mergedItem[rightColumn] === null || mergedItem[rightColumn] === "") {
              mergedItem[rightColumn] = selectedLeftItem[leftColumn];
            }
          }
        }
      }

      setEditModalFormData(mergedItem);
      setShowEditModal(true);
    },
    [componentConfig, selectedLeftItem, activeTabIndex],
  );

  // 수정 모달 저장
  const handleEditModalSave = useCallback(async () => {
    const tableName =
      editModalPanel === "left" ? componentConfig.leftPanel?.tableName : componentConfig.rightPanel?.tableName;

    const sourceColumn = componentConfig.leftPanel?.itemAddConfig?.sourceColumn || "id";
    const primaryKey = editModalItem[sourceColumn] || editModalItem.id || editModalItem.ID;

    if (!tableName || !primaryKey) {
      toast({
        title: "수정 오류",
        description: "테이블명 또는 Primary Key가 없습니다.",
        variant: "destructive",
      });
      return;
    }

    try {
      console.log("📝 데이터 수정:", { tableName, primaryKey, data: editModalFormData });

      // 프론트엔드 전용 필드 제거 (children, level 등)
      const cleanData = { ...editModalFormData };
      delete cleanData.children;
      delete cleanData.level;

      // 좌측 패널 수정 시, 조인 관계 정보 포함
      const updatePayload: any = cleanData;

      if (editModalPanel === "left" && componentConfig.rightPanel?.relation?.type === "join") {
        // 조인 관계가 있는 경우, 관계 정보를 페이로드에 추가
        updatePayload._relationInfo = {
          rightTable: componentConfig.rightPanel.tableName,
          leftColumn: componentConfig.rightPanel.relation.leftColumn,
          rightColumn: componentConfig.rightPanel.relation.rightColumn,
          oldLeftValue: editModalItem[componentConfig.rightPanel.relation.leftColumn],
        };
        console.log("🔗 조인 관계 정보 추가:", updatePayload._relationInfo);
      }

      const result = await dataApi.updateRecord(tableName, primaryKey, updatePayload);

      if (result.success) {
        toast({
          title: "성공",
          description: "데이터가 성공적으로 수정되었습니다.",
        });

        // 모달 닫기
        setShowEditModal(false);
        setEditModalFormData({});
        setEditModalItem(null);

        // 데이터 새로고침
        if (editModalPanel === "left") {
          loadLeftData();
          // 우측 패널도 새로고침 (FK가 변경되었을 수 있음)
          if (selectedLeftItem) {
            loadRightData(selectedLeftItem);
          }
        } else if (editModalPanel === "right" && selectedLeftItem) {
          loadRightData(selectedLeftItem);
        }
      } else {
        toast({
          title: "수정 실패",
          description: result.message || "데이터 수정에 실패했습니다.",
          variant: "destructive",
        });
      }
    } catch (error: any) {
      console.error("데이터 수정 오류:", error);
      toast({
        title: "오류",
        description: error?.response?.data?.message || "데이터 수정 중 오류가 발생했습니다.",
        variant: "destructive",
      });
    }
  }, [
    editModalPanel,
    componentConfig,
    editModalItem,
    editModalFormData,
    toast,
    selectedLeftItem,
    loadLeftData,
    loadRightData,
  ]);

  // 삭제 버튼 핸들러
  const handleDeleteClick = useCallback((panel: "left" | "right", item: any) => {
    setDeleteModalPanel(panel);
    setDeleteModalItem(item);
    setShowDeleteModal(true);
  }, []);

  // 삭제 확인
  const handleDeleteConfirm = useCallback(async () => {
    // 우측 패널 삭제 시 중계 테이블 확인
    let tableName =
      deleteModalPanel === "left" ? componentConfig.leftPanel?.tableName : componentConfig.rightPanel?.tableName;

    // 우측 패널 + 중계 테이블 모드인 경우
    if (deleteModalPanel === "right" && componentConfig.rightPanel?.addConfig?.targetTable) {
      tableName = componentConfig.rightPanel.addConfig.targetTable;
      console.log("🔗 중계 테이블 모드: 삭제 대상 테이블 =", tableName);
    }

    const sourceColumn = componentConfig.leftPanel?.itemAddConfig?.sourceColumn || "id";
    let primaryKey: any = deleteModalItem[sourceColumn] || deleteModalItem.id || deleteModalItem.ID;

    // 복합키 처리: deleteModalItem 전체를 전달 (백엔드에서 복합키 자동 처리)
    if (deleteModalItem && typeof deleteModalItem === "object") {
      primaryKey = deleteModalItem;
      console.log("🔑 복합키 가능성: 전체 객체 전달", primaryKey);
    }

    if (!tableName || !primaryKey) {
      toast({
        title: "삭제 오류",
        description: "테이블명 또는 Primary Key가 없습니다.",
        variant: "destructive",
      });
      return;
    }

    try {
      console.log("🗑️ 데이터 삭제:", { tableName, primaryKey });

      // 🔍 중복 제거 설정 디버깅
      console.log("🔍 중복 제거 디버깅:", {
        panel: deleteModalPanel,
        dataFilter: componentConfig.rightPanel?.dataFilter,
        deduplication: componentConfig.rightPanel?.dataFilter?.deduplication,
        enabled: componentConfig.rightPanel?.dataFilter?.deduplication?.enabled,
      });

      let result;

      // 🔧 중복 제거가 활성화된 경우, groupByColumn 기준으로 모든 관련 레코드 삭제
      if (deleteModalPanel === "right" && componentConfig.rightPanel?.dataFilter?.deduplication?.enabled) {
        const deduplication = componentConfig.rightPanel.dataFilter.deduplication;
        const groupByColumn = deduplication.groupByColumn;

        if (groupByColumn && deleteModalItem[groupByColumn]) {
          const groupValue = deleteModalItem[groupByColumn];
          console.log(`🔗 중복 제거 활성화: ${groupByColumn} = ${groupValue} 기준으로 모든 레코드 삭제`);

          // groupByColumn 값으로 필터링하여 삭제
          const filterConditions: Record<string, any> = {
            [groupByColumn]: groupValue,
          };

          // 좌측 패널의 선택된 항목 정보도 포함 (customer_id 등)
          if (selectedLeftItem && componentConfig.rightPanel?.mode === "join") {
            const leftColumn = componentConfig.rightPanel.join.leftColumn;
            const rightColumn = componentConfig.rightPanel.join.rightColumn;
            filterConditions[rightColumn] = selectedLeftItem[leftColumn];
          }

          console.log("🗑️ 그룹 삭제 조건:", filterConditions);

          // 그룹 삭제 API 호출
          result = await dataApi.deleteGroupRecords(tableName, filterConditions);
        } else {
          // 단일 레코드 삭제
          result = await dataApi.deleteRecord(tableName, primaryKey);
        }
      } else {
        // 단일 레코드 삭제
        result = await dataApi.deleteRecord(tableName, primaryKey);
      }

      if (result.success) {
        toast({
          title: "성공",
          description: "데이터가 성공적으로 삭제되었습니다.",
        });

        // 모달 닫기
        setShowDeleteModal(false);
        setDeleteModalItem(null);

        // 데이터 새로고침
        if (deleteModalPanel === "left") {
          loadLeftData();
          // 삭제된 항목이 선택되어 있었으면 선택 해제
          if (selectedLeftItem && selectedLeftItem[sourceColumn] === primaryKey) {
            setSelectedLeftItem(null);
            setRightData(null);
          }
        } else if (deleteModalPanel === "right" && selectedLeftItem) {
          loadRightData(selectedLeftItem);
        }
      } else {
        toast({
          title: "삭제 실패",
          description: result.message || "데이터 삭제에 실패했습니다.",
          variant: "destructive",
        });
      }
    } catch (error: any) {
      console.error("데이터 삭제 오류:", error);

      // 외래키 제약조건 에러 처리
      let errorMessage = "데이터 삭제 중 오류가 발생했습니다.";
      if (error?.response?.data?.error?.includes("foreign key")) {
        errorMessage = "이 데이터를 참조하는 다른 데이터가 있어 삭제할 수 없습니다.";
      }

      toast({
        title: "오류",
        description: errorMessage,
        variant: "destructive",
      });
    }
  }, [deleteModalPanel, componentConfig, deleteModalItem, toast, selectedLeftItem, loadLeftData, loadRightData]);

  // 항목별 추가 버튼 핸들러 (좌측 항목의 + 버튼 - 하위 항목 추가)
  const handleItemAddClick = useCallback(
    (item: any) => {
      const itemAddConfig = componentConfig.leftPanel?.itemAddConfig;

      if (!itemAddConfig) {
        toast({
          title: "설정 오류",
          description: "하위 항목 추가 설정이 없습니다.",
          variant: "destructive",
        });
        return;
      }

      const { sourceColumn, parentColumn } = itemAddConfig;

      if (!sourceColumn || !parentColumn) {
        toast({
          title: "설정 오류",
          description: "현재 항목 ID 컬럼과 상위 항목 저장 컬럼을 설정해주세요.",
          variant: "destructive",
        });
        return;
      }

      // 선택된 항목의 sourceColumn 값을 가져와서 parentColumn에 매핑
      const sourceValue = item[sourceColumn];

      if (!sourceValue) {
        toast({
          title: "데이터 오류",
          description: `선택한 항목의 ${sourceColumn} 값이 없습니다.`,
          variant: "destructive",
        });
        return;
      }

      // 좌측 패널 추가 모달 열기 (parentColumn 값 미리 채우기)
      setAddModalPanel("left-item");
      setAddModalFormData({ [parentColumn]: sourceValue });
      setShowAddModal(true);
    },
    [componentConfig, toast],
  );

  // 추가 모달 저장
  const handleAddModalSave = useCallback(async () => {
    // 테이블명과 모달 컬럼 결정
    let tableName: string | undefined;
    let modalColumns: Array<{ name: string; label: string; required?: boolean }> | undefined;
    const finalData = { ...addModalFormData };

    if (addModalPanel === "left") {
      tableName = componentConfig.leftPanel?.tableName;
      modalColumns = componentConfig.leftPanel?.addModalColumns;
    } else if (addModalPanel === "right") {
      // 우측 패널: 중계 테이블 설정이 있는지 확인
      const addConfig = componentConfig.rightPanel?.addConfig;

      if (addConfig?.targetTable) {
        // 중계 테이블 모드
        tableName = addConfig.targetTable;
        modalColumns = componentConfig.rightPanel?.addModalColumns;

        // 좌측 패널에서 선택된 값 자동 채우기
        if (addConfig.leftPanelColumn && addConfig.targetColumn && selectedLeftItem) {
          const leftValue = selectedLeftItem[addConfig.leftPanelColumn];
          finalData[addConfig.targetColumn] = leftValue;
          console.log(`🔗 좌측 패널 값 자동 채움: ${addConfig.targetColumn} = ${leftValue}`);
        }

        // 자동 채움 컬럼 추가
        if (addConfig.autoFillColumns) {
          Object.entries(addConfig.autoFillColumns).forEach(([key, value]) => {
            finalData[key] = value;
          });
          console.log("🔧 자동 채움 컬럼:", addConfig.autoFillColumns);
        }
      } else {
        // 일반 테이블 모드
        tableName = componentConfig.rightPanel?.tableName;
        modalColumns = componentConfig.rightPanel?.addModalColumns;
      }
    } else if (addModalPanel === "left-item") {
      // 하위 항목 추가 (좌측 테이블에 추가)
      tableName = componentConfig.leftPanel?.tableName;
      modalColumns = componentConfig.leftPanel?.itemAddConfig?.addModalColumns;
    }

    if (!tableName) {
      toast({
        title: "테이블 오류",
        description: "테이블명이 설정되지 않았습니다.",
        variant: "destructive",
      });
      return;
    }

    // 필수 필드 검증
    const requiredFields = (modalColumns || []).filter((col) => col.required);
    for (const field of requiredFields) {
      if (!addModalFormData[field.name]) {
        toast({
          title: "입력 오류",
          description: `${field.label}은(는) 필수 입력 항목입니다.`,
          variant: "destructive",
        });
        return;
      }
    }

    try {
      console.log("📝 데이터 추가:", { tableName, data: finalData });

      const result = await dataApi.createRecord(tableName, finalData);

      if (result.success) {
        toast({
          title: "성공",
          description: "데이터가 성공적으로 추가되었습니다.",
        });

        // 모달 닫기
        setShowAddModal(false);
        setAddModalFormData({});

        // 데이터 새로고침
        if (addModalPanel === "left" || addModalPanel === "left-item") {
          // 좌측 패널 데이터 새로고침 (일반 추가 또는 하위 항목 추가)
          loadLeftData();
        } else if (addModalPanel === "right" && selectedLeftItem) {
          // 우측 패널 데이터 새로고침
          loadRightData(selectedLeftItem);
        }
      } else {
        toast({
          title: "저장 실패",
          description: result.message || "데이터 추가에 실패했습니다.",
          variant: "destructive",
        });
      }
    } catch (error: any) {
      console.error("데이터 추가 오류:", error);

      // 에러 메시지 추출
      let errorMessage = "데이터 추가 중 오류가 발생했습니다.";

      if (error?.response?.data) {
        const responseData = error.response.data;

        // 백엔드에서 반환한 에러 메시지 확인
        if (responseData.error) {
          // 중복 키 에러 처리
          if (responseData.error.includes("duplicate key")) {
            errorMessage = "이미 존재하는 값입니다. 다른 값을 입력해주세요.";
          }
          // NOT NULL 제약조건 에러
          else if (responseData.error.includes("null value")) {
            const match = responseData.error.match(/column "(\w+)"/);
            const columnName = match ? match[1] : "필수";
            errorMessage = `${columnName} 필드는 필수 입력 항목입니다.`;
          }
          // 외래키 제약조건 에러
          else if (responseData.error.includes("foreign key")) {
            errorMessage = "참조하는 데이터가 존재하지 않습니다.";
          }
          // 기타 에러
          else {
            errorMessage = responseData.message || responseData.error;
          }
        } else if (responseData.message) {
          errorMessage = responseData.message;
        }
      }

      toast({
        title: "오류",
        description: errorMessage,
        variant: "destructive",
      });
    }
  }, [addModalPanel, componentConfig, addModalFormData, toast, selectedLeftItem, loadLeftData, loadRightData]);

  // 🔧 좌측 컬럼 가시성 설정 저장 및 불러오기
  useEffect(() => {
    const leftTableName = componentConfig.leftPanel?.tableName;
    if (leftTableName && currentUserId) {
      // localStorage에서 저장된 설정 불러오기
      const storageKey = `table_column_visibility_${leftTableName}_${currentUserId}`;
      const savedSettings = localStorage.getItem(storageKey);

      if (savedSettings) {
        try {
          const parsed = JSON.parse(savedSettings) as ColumnVisibility[];
          setLeftColumnVisibility(parsed);
        } catch (error) {
          console.error("저장된 컬럼 설정 불러오기 실패:", error);
        }
      }
    }
  }, [componentConfig.leftPanel?.tableName, currentUserId]);

  // 🔧 컬럼 가시성 변경 시 localStorage에 저장 및 순서 업데이트
  useEffect(() => {
    const leftTableName = componentConfig.leftPanel?.tableName;

    if (leftColumnVisibility.length > 0 && leftTableName && currentUserId) {
      // 순서 업데이트
      const newOrder = leftColumnVisibility.map((cv) => cv.columnName).filter((name) => name !== "__checkbox__"); // 체크박스 제외

      setLeftColumnOrder(newOrder);

      // localStorage에 저장
      const storageKey = `table_column_visibility_${leftTableName}_${currentUserId}`;
      localStorage.setItem(storageKey, JSON.stringify(leftColumnVisibility));
    }
  }, [leftColumnVisibility, componentConfig.leftPanel?.tableName, currentUserId]);

  // 초기 데이터 로드
  useEffect(() => {
    if (!isDesignMode && componentConfig.autoLoad !== false) {
      loadLeftData();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isDesignMode, componentConfig.autoLoad]);

  // 🔄 필터 변경 시 데이터 다시 로드
  useEffect(() => {
    if (!isDesignMode && componentConfig.autoLoad !== false) {
      loadLeftData();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [leftFilters]);

  // 🆕 전역 테이블 새로고침 이벤트 리스너
  useEffect(() => {
    const handleRefreshTable = () => {
      if (!isDesignMode) {
        console.log("🔄 [SplitPanel] refreshTable 이벤트 수신 - 데이터 새로고침");
        loadLeftData();
        // 선택된 항목이 있으면 우측 패널도 새로고침
        if (selectedLeftItem) {
          loadRightData(selectedLeftItem);
        }
      }
    };

    window.addEventListener("refreshTable", handleRefreshTable);

    return () => {
      window.removeEventListener("refreshTable", handleRefreshTable);
    };
  }, [isDesignMode, loadLeftData, loadRightData, selectedLeftItem]);

  // 리사이저 드래그 핸들러
  const handleMouseDown = (e: React.MouseEvent) => {
    if (!resizable) return;
    setIsDragging(true);
    e.preventDefault();
  };

  const handleMouseMove = useCallback(
    (e: MouseEvent) => {
      if (!isDragging || !containerRef.current) return;

      const containerRect = containerRef.current.getBoundingClientRect();
      const containerWidth = containerRect.width;
      const relativeX = e.clientX - containerRect.left;
      const newLeftWidth = (relativeX / containerWidth) * 100;

      // 최소/최대 너비 제한 (20% ~ 80%)
      if (newLeftWidth >= 20 && newLeftWidth <= 80) {
        setLeftWidth(newLeftWidth);
      }
    },
    [isDragging],
  );

  const handleMouseUp = useCallback(() => {
    setIsDragging(false);
  }, []);

  React.useEffect(() => {
    if (isDragging) {
      // 드래그 중에는 텍스트 선택 방지
      document.body.style.userSelect = "none";
      document.body.style.cursor = "col-resize";

      document.addEventListener("mousemove", handleMouseMove);
      document.addEventListener("mouseup", handleMouseUp);

      return () => {
        document.body.style.userSelect = "";
        document.body.style.cursor = "";
        document.removeEventListener("mousemove", handleMouseMove);
        document.removeEventListener("mouseup", handleMouseUp);
      };
    }
  }, [isDragging, handleMouseMove, handleMouseUp]);

  return (
    <div
      ref={containerRef}
      style={{
        ...componentStyle,
        display: "flex",
        flexDirection: "row",
      }}
      onClick={(e) => {
        if (isDesignMode) {
          e.stopPropagation();
          onClick?.(e);
        }
      }}
      className="w-full overflow-hidden rounded-lg bg-white shadow-sm"
    >
      {/* 좌측 패널 */}
      <div
        style={{ width: `${leftWidth}%`, minWidth: isDesignMode ? `${minLeftWidth}px` : "0", height: "100%" }}
        className="border-border flex flex-shrink-0 flex-col border-r"
      >
        <Card className="flex flex-col border-0 shadow-none" style={{ height: "100%" }}>
          <CardHeader
            className="flex-shrink-0 border-b"
            style={{
              height: componentConfig.leftPanel?.panelHeaderHeight || 48,
              minHeight: componentConfig.leftPanel?.panelHeaderHeight || 48,
              padding: "0 1rem",
              display: "flex",
              alignItems: "center",
            }}
          >
            <div className="flex w-full items-center justify-between">
              <CardTitle className="text-base font-semibold">
                {componentConfig.leftPanel?.title || "좌측 패널"}
              </CardTitle>
              {!isDesignMode && componentConfig.leftPanel?.showAdd && (
                <Button size="sm" variant="outline" onClick={() => handleAddClick("left")}>
                  <Plus className="mr-1 h-4 w-4" />
                  추가
                </Button>
              )}
            </div>
          </CardHeader>
          {componentConfig.leftPanel?.showSearch && (
            <div className="flex-shrink-0 border-b p-2">
              <div className="relative">
                <Search className="text-muted-foreground absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2" />
                <Input
                  placeholder="검색..."
                  value={leftSearchQuery}
                  onChange={(e) => setLeftSearchQuery(e.target.value)}
                  className="pl-9"
                />
              </div>
            </div>
          )}
          <CardContent className="flex-1 overflow-auto p-4">
            {/* 좌측 데이터 목록/테이블 */}
            {componentConfig.leftPanel?.displayMode === "table" ? (
              // 테이블 모드
              <div className="w-full">
                {isDesignMode ? (
                  // 디자인 모드: 샘플 테이블
                  <div className="overflow-auto">
                    <table className="min-w-full divide-y divide-border">
                      <thead className="bg-muted">
                        <tr>
                          <th className="px-3 py-2 text-left text-xs font-medium text-muted-foreground uppercase">컬럼 1</th>
                          <th className="px-3 py-2 text-left text-xs font-medium text-muted-foreground uppercase">컬럼 2</th>
                          <th className="px-3 py-2 text-left text-xs font-medium text-muted-foreground uppercase">컬럼 3</th>
                        </tr>
                      </thead>
                      <tbody className="divide-y divide-border bg-white">
                        <tr className="cursor-pointer hover:bg-muted">
                          <td className="px-3 py-2 text-sm whitespace-nowrap">데이터 1-1</td>
                          <td className="px-3 py-2 text-sm whitespace-nowrap">데이터 1-2</td>
                          <td className="px-3 py-2 text-sm whitespace-nowrap">데이터 1-3</td>
                        </tr>
                        <tr className="cursor-pointer hover:bg-muted">
                          <td className="px-3 py-2 text-sm whitespace-nowrap">데이터 2-1</td>
                          <td className="px-3 py-2 text-sm whitespace-nowrap">데이터 2-2</td>
                          <td className="px-3 py-2 text-sm whitespace-nowrap">데이터 2-3</td>
                        </tr>
                      </tbody>
                    </table>
                  </div>
                ) : isLoadingLeft ? (
                  <div className="flex items-center justify-center py-8">
                    <Loader2 className="text-primary h-6 w-6 animate-spin" />
                    <span className="text-muted-foreground ml-2 text-sm">데이터를 불러오는 중...</span>
                  </div>
                ) : (
                  (() => {
                    // 🆕 그룹별 합산된 데이터 사용
                    const dataSource = summedLeftData;
                    console.log(
                      "🔍 [테이블모드 렌더링] dataSource 개수:",
                      dataSource.length,
                      "leftGroupSumConfig:",
                      leftGroupSumConfig,
                    );

                    // 🔧 로컬 검색 필터 적용
                    const filteredData = leftSearchQuery
                      ? dataSource.filter((item) => {
                          const searchLower = leftSearchQuery.toLowerCase();
                          return Object.entries(item).some(([key, value]) => {
                            if (value === null || value === undefined) return false;
                            return String(value).toLowerCase().includes(searchLower);
                          });
                        })
                      : dataSource;

                    // 🔧 가시성 처리된 컬럼 사용
                    const columnsToShow =
                      visibleLeftColumns.length > 0
                        ? visibleLeftColumns.map((col: any) => {
                            const colName = typeof col === "string" ? col : col.name || col.columnName;
                            return {
                              name: colName,
                              label:
                                leftColumnLabels[colName] || (typeof col === "object" ? col.label : null) || colName,
                              width: typeof col === "object" ? col.width : 150,
                              align: (typeof col === "object" ? col.align : "left") as "left" | "center" | "right",
                              format: typeof col === "object" ? col.format : undefined, // 🆕 포맷 설정 포함
                            };
                          })
                        : Object.keys(filteredData[0] || {})
                            .filter((key) => key !== "children" && key !== "level")
                            .slice(0, 5)
                            .map((key) => ({
                              name: key,
                              label: leftColumnLabels[key] || key,
                              width: 150,
                              align: "left" as const,
                              format: undefined, // 🆕 기본값
                            }));

                    // 🔧 그룹화된 데이터 렌더링
                    if (groupedLeftData.length > 0) {
                      return (
                        <div className="overflow-auto">
                          {groupedLeftData.map((group, groupIdx) => (
                            <div key={groupIdx} className="mb-4">
                              <div className="bg-muted px-3 py-2 text-sm font-semibold">
                                {group.groupKey} ({group.count}개)
                              </div>
                              <table className="min-w-full divide-y divide-border">
                                <thead className="bg-muted">
                                  <tr>
                                    {columnsToShow.map((col, idx) => (
                                      <th
                                        key={idx}
                                        className="px-3 py-2 text-left text-xs font-medium tracking-wider text-muted-foreground uppercase"
                                        style={{
                                          width: col.width ? `${col.width}px` : "auto",
                                          textAlign: col.align || "left",
                                        }}
                                      >
                                        {col.label}
                                      </th>
                                    ))}
                                  </tr>
                                </thead>
                                <tbody className="divide-y divide-border bg-white">
                                  {group.items.map((item, idx) => {
                                    const sourceColumn = componentConfig.leftPanel?.itemAddConfig?.sourceColumn || "id";
                                    const itemId = item[sourceColumn] || item.id || item.ID;
                                    const isSelected =
                                      selectedLeftItem &&
                                      (selectedLeftItem[sourceColumn] === itemId || selectedLeftItem === item);

                                    return (
                                      <tr
                                        key={itemId != null ? `${itemId}-${idx}` : idx}
                                        onClick={() => handleLeftItemSelect(item)}
                                        className={`hover:bg-accent cursor-pointer transition-colors ${
                                          isSelected ? "bg-primary/10" : ""
                                        }`}
                                      >
                                        {columnsToShow.map((col, colIdx) => (
                                          <td
                                            key={colIdx}
                                            className="px-3 py-2 text-sm whitespace-nowrap text-foreground"
                                            style={{ textAlign: col.align || "left", overflow: "hidden", textOverflow: "ellipsis" }}
                                          >
                                            {formatCellValue(
                                              col.name,
                                              getEntityJoinValue(item, col.name),
                                              leftCategoryMappings,
                                              col.format,
                                            )}
                                          </td>
                                        ))}
                                      </tr>
                                    );
                                  })}
                                </tbody>
                              </table>
                            </div>
                          ))}
                        </div>
                      );
                    }

                    // 🔧 일반 테이블 렌더링 (그룹화 없음)
                    return (
                      <div className="overflow-auto">
                        <table className="min-w-full divide-y divide-border">
                          <thead className="sticky top-0 z-10 bg-muted">
                            <tr>
                              {columnsToShow.map((col, idx) => (
                                <th
                                  key={idx}
                                  className="px-3 py-2 text-left text-xs font-medium tracking-wider text-muted-foreground uppercase"
                                  style={{
                                    width: col.width ? `${col.width}px` : "auto",
                                    minWidth: "80px",
                                    textAlign: col.align || "left",
                                  }}
                                >
                                  {col.label}
                                </th>
                              ))}
                            </tr>
                          </thead>
                          <tbody className="divide-y divide-border bg-white">
                            {filteredData.map((item, idx) => {
                              const sourceColumn = componentConfig.leftPanel?.itemAddConfig?.sourceColumn || "id";
                              const itemId = item[sourceColumn] || item.id || item.ID;
                              const isSelected =
                                selectedLeftItem &&
                                (selectedLeftItem[sourceColumn] === itemId || selectedLeftItem === item);

                              return (
                                <tr
                                  key={itemId != null ? `${itemId}-${idx}` : idx}
                                  onClick={() => handleLeftItemSelect(item)}
                                  className={`hover:bg-accent cursor-pointer transition-colors ${
                                    isSelected ? "bg-primary/10" : ""
                                  }`}
                                >
                                  {columnsToShow.map((col, colIdx) => (
                                    <td
                                      key={colIdx}
                                      className="px-3 py-2 text-sm whitespace-nowrap text-foreground"
                                      style={{ textAlign: col.align || "left", overflow: "hidden", textOverflow: "ellipsis" }}
                                    >
                                      {formatCellValue(
                                        col.name,
                                        getEntityJoinValue(item, col.name),
                                        leftCategoryMappings,
                                        col.format,
                                      )}
                                    </td>
                                  ))}
                                </tr>
                              );
                            })}
                          </tbody>
                        </table>
                      </div>
                    );
                  })()
                )}
              </div>
            ) : (
              // 목록 모드 (기존)
              <div className="space-y-1">
                {isDesignMode ? (
                  // 디자인 모드: 샘플 데이터
                  <>
                    <div
                      onClick={() => handleLeftItemSelect({ id: 1, name: "항목 1" })}
                      className={`hover:bg-accent cursor-pointer rounded-md p-3 transition-colors ${
                        selectedLeftItem?.id === 1 ? "bg-primary/10 text-primary" : ""
                      }`}
                    >
                      <div className="font-medium">항목 1</div>
                      <div className="text-muted-foreground text-xs">설명 텍스트</div>
                    </div>
                    <div
                      onClick={() => handleLeftItemSelect({ id: 2, name: "항목 2" })}
                      className={`hover:bg-accent cursor-pointer rounded-md p-3 transition-colors ${
                        selectedLeftItem?.id === 2 ? "bg-primary/10 text-primary" : ""
                      }`}
                    >
                      <div className="font-medium">항목 2</div>
                      <div className="text-muted-foreground text-xs">설명 텍스트</div>
                    </div>
                    <div
                      onClick={() => handleLeftItemSelect({ id: 3, name: "항목 3" })}
                      className={`hover:bg-accent cursor-pointer rounded-md p-3 transition-colors ${
                        selectedLeftItem?.id === 3 ? "bg-primary/10 text-primary" : ""
                      }`}
                    >
                      <div className="font-medium">항목 3</div>
                      <div className="text-muted-foreground text-xs">설명 텍스트</div>
                    </div>
                  </>
                ) : isLoadingLeft ? (
                  // 로딩 중
                  <div className="flex items-center justify-center py-8">
                    <Loader2 className="text-primary h-6 w-6 animate-spin" />
                    <span className="text-muted-foreground ml-2 text-sm">데이터를 불러오는 중...</span>
                  </div>
                ) : (
                  (() => {
                    // 🆕 그룹별 합산된 데이터 사용
                    const dataToDisplay = summedLeftData;
                    console.log(
                      "🔍 [렌더링] dataToDisplay 개수:",
                      dataToDisplay.length,
                      "leftGroupSumConfig:",
                      leftGroupSumConfig,
                    );

                    // 검색 필터링 (클라이언트 사이드)
                    const filteredLeftData = leftSearchQuery
                      ? dataToDisplay.filter((item) => {
                          const searchLower = leftSearchQuery.toLowerCase();
                          return Object.entries(item).some(([key, value]) => {
                            if (value === null || value === undefined) return false;
                            return String(value).toLowerCase().includes(searchLower);
                          });
                        })
                      : dataToDisplay;

                    // 재귀 렌더링 함수
                    const renderTreeItem = (item: any, index: number): React.ReactNode => {
                      const sourceColumn = componentConfig.leftPanel?.itemAddConfig?.sourceColumn || "id";
                      const rawItemId = item[sourceColumn] || item.id || item.ID;
                      const itemId = rawItemId != null ? rawItemId : index;
                      const isSelected =
                        selectedLeftItem && (selectedLeftItem[sourceColumn] === itemId || selectedLeftItem === item);
                      const hasChildren = item.children && item.children.length > 0;
                      const isExpanded = expandedItems.has(itemId);
                      const level = item.level || 0;

                      // 🔧 수정: "표시할 컬럼 선택"에서 설정한 컬럼을 우선 사용
                      const configuredColumns = componentConfig.leftPanel?.columns || [];
                      let displayFields: { label: string; value: any }[] = [];

                      // 디버그 로그
                      if (index === 0) {
                        console.log("🔍 좌측 패널 표시 로직:");
                        console.log("  - 설정된 표시 컬럼:", configuredColumns);
                        console.log("  - item keys:", Object.keys(item));
                      }

                      if (configuredColumns.length > 0) {
                        // 🔧 "표시할 컬럼 선택"에서 설정한 컬럼 사용
                        displayFields = configuredColumns.slice(0, 2).map((col: any) => {
                          const colName = typeof col === "string" ? col : col.name || col.columnName;
                          const colLabel = typeof col === "object" ? col.label : leftColumnLabels[colName] || colName;
                          return {
                            label: colLabel,
                            value: item[colName],
                          };
                        });

                        if (index === 0) {
                          console.log("  ✅ 설정된 컬럼 기반 표시:", displayFields);
                        }
                      } else {
                        // 설정된 컬럼이 없으면 자동으로 첫 2개 필드 표시
                        const keys = Object.keys(item).filter(
                          (k) => k !== "id" && k !== "ID" && k !== "children" && k !== "level" && shouldShowField(k),
                        );
                        displayFields = keys.slice(0, 2).map((key) => ({
                          label: leftColumnLabels[key] || key,
                          value: item[key],
                        }));

                        if (index === 0) {
                          console.log("  ⚠️ 설정된 컬럼 없음, 자동 선택:", displayFields);
                        }
                      }

                      const displayTitle = displayFields[0]?.value || item.name || item.title || `항목 ${index + 1}`;
                      const displaySubtitle = displayFields[1]?.value || null;

                      return (
                        <React.Fragment key={`${itemId}-${index}`}>
                          {/* 현재 항목 */}
                          <div
                            className={`group hover:bg-muted relative cursor-pointer rounded-md p-3 transition-colors ${
                              isSelected ? "bg-primary/10 text-primary" : "text-foreground"
                            }`}
                            style={{ paddingLeft: `${12 + level * 24}px` }}
                          >
                            <div
                              className="flex items-center gap-2"
                              onClick={() => {
                                handleLeftItemSelect(item);
                                if (hasChildren) {
                                  toggleExpand(itemId);
                                }
                              }}
                            >
                              {/* 펼치기/접기 아이콘 */}
                              {hasChildren ? (
                                <div className="flex-shrink-0">
                                  {isExpanded ? (
                                    <ChevronDown className="h-4 w-4 text-muted-foreground" />
                                  ) : (
                                    <ChevronRight className="h-4 w-4 text-muted-foreground" />
                                  )}
                                </div>
                              ) : (
                                <div className="w-5" />
                              )}

                              {/* 항목 내용 */}
                              <div className="min-w-0 flex-1">
                                <div className="truncate font-medium">{displayTitle}</div>
                                {displaySubtitle && (
                                  <div className="text-muted-foreground truncate text-xs">{displaySubtitle}</div>
                                )}
                              </div>

                              {/* 항목별 버튼들 */}
                              {!isDesignMode && (
                                <div className="flex flex-shrink-0 items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100">
                                  {/* 수정 버튼 */}
                                  <button
                                    onClick={(e) => {
                                      e.stopPropagation();
                                      handleEditClick("left", item);
                                    }}
                                    className="rounded p-1 transition-colors hover:bg-muted/80"
                                    title="수정"
                                  >
                                    <Pencil className="h-4 w-4 text-muted-foreground" />
                                  </button>

                                  {/* 삭제 버튼 */}
                                  <button
                                    onClick={(e) => {
                                      e.stopPropagation();
                                      handleDeleteClick("left", item);
                                    }}
                                    className="rounded p-1 transition-colors hover:bg-destructive/10"
                                    title="삭제"
                                  >
                                    <Trash2 className="h-4 w-4 text-destructive" />
                                  </button>

                                  {/* 항목별 추가 버튼 */}
                                  {componentConfig.leftPanel?.showItemAddButton && (
                                    <button
                                      onClick={(e) => {
                                        e.stopPropagation();
                                        handleItemAddClick(item);
                                      }}
                                      className="rounded p-1 transition-colors hover:bg-muted/80"
                                      title="하위 항목 추가"
                                    >
                                      <Plus className="h-4 w-4 text-muted-foreground" />
                                    </button>
                                  )}
                                </div>
                              )}
                            </div>
                          </div>

                          {/* 자식 항목들 (접혀있으면 표시 안함) */}
                          {hasChildren &&
                            isExpanded &&
                            item.children.map((child: any, childIndex: number) => renderTreeItem(child, childIndex))}
                        </React.Fragment>
                      );
                    };

                    return filteredLeftData.length > 0 ? (
                      // 실제 데이터 표시
                      filteredLeftData.map((item, index) => renderTreeItem(item, index))
                    ) : (
                      // 검색 결과 없음
                      <div className="text-muted-foreground py-8 text-center text-sm">
                        {leftSearchQuery ? (
                          <>
                            <p>검색 결과가 없습니다.</p>
                            <p className="text-muted-foreground/70 mt-1 text-xs">다른 검색어를 입력해보세요.</p>
                          </>
                        ) : (
                          "데이터가 없습니다."
                        )}
                      </div>
                    );
                  })()
                )}
              </div>
            )}
          </CardContent>
        </Card>
      </div>

      {/* 리사이저 */}
      {resizable && (
        <div
          onMouseDown={handleMouseDown}
          className="group bg-border hover:bg-primary flex w-1 cursor-col-resize items-center justify-center transition-colors"
        >
          <GripVertical className="text-muted-foreground group-hover:text-primary-foreground h-4 w-4" />
        </div>
      )}

      {/* 우측 패널 */}
      <div
        style={{ width: `${100 - leftWidth}%`, minWidth: isDesignMode ? `${minRightWidth}px` : "0", height: "100%" }}
        className="flex flex-shrink-0 flex-col"
      >
        <Card className="flex flex-col border-0 shadow-none" style={{ height: "100%" }}>
          {/* 🆕 탭 바 (추가 탭이 있을 때만 표시) */}
          {(componentConfig.rightPanel?.additionalTabs?.length || 0) > 0 && (
            <div className="flex-shrink-0 border-b">
              <Tabs
                value={String(activeTabIndex)}
                onValueChange={(value) => handleTabChange(Number(value))}
                className="w-full"
              >
                <TabsList className="h-9 w-full justify-start rounded-none border-b-0 bg-transparent p-0 px-2">
                  <TabsTrigger
                    value="0"
                    className="h-8 rounded-none border-b-2 border-transparent px-4 data-[state=active]:border-primary data-[state=active]:bg-transparent data-[state=active]:shadow-none"
                  >
                    {componentConfig.rightPanel?.title || "기본"}
                  </TabsTrigger>
                  {componentConfig.rightPanel?.additionalTabs?.map((tab, index) => (
                    <TabsTrigger
                      key={tab.tabId}
                      value={String(index + 1)}
                      className="h-8 rounded-none border-b-2 border-transparent px-4 data-[state=active]:border-primary data-[state=active]:bg-transparent data-[state=active]:shadow-none"
                    >
                      {tab.label || `탭 ${index + 1}`}
                    </TabsTrigger>
                  ))}
                </TabsList>
              </Tabs>
            </div>
          )}
          <CardHeader
            className="flex-shrink-0 border-b"
            style={{
              height: componentConfig.rightPanel?.panelHeaderHeight || 48,
              minHeight: componentConfig.rightPanel?.panelHeaderHeight || 48,
              padding: "0 1rem",
              display: "flex",
              alignItems: "center",
            }}
          >
            <div className="flex w-full items-center justify-between">
              <CardTitle className="text-base font-semibold">
                {activeTabIndex === 0
                  ? componentConfig.rightPanel?.title || "우측 패널"
                  : componentConfig.rightPanel?.additionalTabs?.[activeTabIndex - 1]?.title ||
                    componentConfig.rightPanel?.additionalTabs?.[activeTabIndex - 1]?.label ||
                    "우측 패널"}
              </CardTitle>
              {!isDesignMode && (
                <div className="flex items-center gap-2">
                  {/* 🆕 현재 활성 탭에 따른 추가 버튼 */}
                  {activeTabIndex === 0
                    ? componentConfig.rightPanel?.showAdd && (
                        <Button size="sm" variant="outline" onClick={() => handleAddClick("right")}>
                          <Plus className="mr-1 h-4 w-4" />
                          추가
                        </Button>
                      )
                    : componentConfig.rightPanel?.additionalTabs?.[activeTabIndex - 1]?.showAdd && (
                        <Button size="sm" variant="outline" onClick={() => handleAddClick("right")}>
                          <Plus className="mr-1 h-4 w-4" />
                          추가
                        </Button>
                      )}
                  {/* 우측 패널 수정/삭제는 각 카드에서 처리 */}
                </div>
              )}
            </div>
          </CardHeader>
          {componentConfig.rightPanel?.showSearch && (
            <div className="flex-shrink-0 border-b p-2">
              <div className="relative">
                <Search className="text-muted-foreground absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2" />
                <Input
                  placeholder="검색..."
                  value={rightSearchQuery}
                  onChange={(e) => setRightSearchQuery(e.target.value)}
                  className="pl-9"
                />
              </div>
            </div>
          )}
          <CardContent className="flex-1 overflow-auto p-4">
            {/* 🆕 추가 탭 데이터 렌더링 */}
            {activeTabIndex > 0 ? (
              // 추가 탭 컨텐츠
              (() => {
                const currentTabConfig = componentConfig.rightPanel?.additionalTabs?.[activeTabIndex - 1];
                const currentTabData = tabsData[activeTabIndex] || [];
                const isTabLoading = tabsLoading[activeTabIndex];

                if (isTabLoading) {
                  return (
                    <div className="flex h-full items-center justify-center">
                      <div className="text-center">
                        <Loader2 className="text-primary mx-auto h-8 w-8 animate-spin" />
                        <p className="text-muted-foreground mt-2 text-sm">데이터를 불러오는 중...</p>
                      </div>
                    </div>
                  );
                }

                if (!selectedLeftItem) {
                  return (
                    <div className="flex h-full items-center justify-center">
                      <p className="text-muted-foreground text-sm">좌측에서 항목을 선택하세요</p>
                    </div>
                  );
                }

                if (currentTabData.length === 0) {
                  return (
                    <div className="flex h-full items-center justify-center">
                      <p className="text-muted-foreground text-sm">데이터가 없습니다</p>
                    </div>
                  );
                }

                // 탭 데이터 렌더링 (목록/테이블 모드)
                const isTableMode = currentTabConfig?.displayMode === "table";

                if (isTableMode) {
                  // 테이블 모드
                  const displayColumns = currentTabConfig?.columns || [];
                  const columnsToShow =
                    displayColumns.length > 0
                      ? displayColumns.map((col) => ({
                          ...col,
                          label: col.label || col.name,
                        }))
                      : Object.keys(currentTabData[0] || {})
                          .filter(shouldShowField)
                          .slice(0, 8)
                          .map((key) => ({ name: key, label: key }));

                  return (
                    <div className="overflow-auto rounded-lg border">
                      <table className="w-full text-sm">
                        <thead className="bg-muted/50 sticky top-0">
                          <tr>
                            {columnsToShow.map((col: any) => (
                              <th
                                key={col.name}
                                className="px-3 py-2 text-left font-medium"
                                style={{ width: col.width ? `${col.width}px` : "auto" }}
                              >
                                {col.label}
                              </th>
                            ))}
                            {(currentTabConfig?.showEdit || currentTabConfig?.showDelete) && (
                              <th className="w-20 px-3 py-2 text-center font-medium">작업</th>
                            )}
                          </tr>
                        </thead>
                        <tbody>
                          {currentTabData.map((item: any, idx: number) => (
                            <tr key={item.id || idx} className="hover:bg-muted/30 border-t">
                              {columnsToShow.map((col: any) => (
                                <td key={col.name} className="px-3 py-2">
                                  {formatCellValue(col.name, item[col.name], {}, col.format)}
                                </td>
                              ))}
                              {(currentTabConfig?.showEdit || currentTabConfig?.showDelete) && (
                                <td className="px-3 py-2 text-center">
                                  <div className="flex items-center justify-center gap-1">
                                    {currentTabConfig?.showEdit && (
                                      <Button
                                        variant="ghost"
                                        size="sm"
                                        className="h-7 w-7 p-0"
                                        onClick={() => handleEditClick("right", item)}
                                      >
                                        <Pencil className="h-3.5 w-3.5" />
                                      </Button>
                                    )}
                                    {currentTabConfig?.showDelete && (
                                      <Button
                                        variant="ghost"
                                        size="sm"
                                        className="h-7 w-7 p-0 text-destructive hover:text-destructive"
                                        onClick={() => handleDeleteClick("right", item)}
                                      >
                                        <Trash2 className="h-3.5 w-3.5" />
                                      </Button>
                                    )}
                                  </div>
                                </td>
                              )}
                            </tr>
                          ))}
                        </tbody>
                      </table>
                    </div>
                  );
                } else {
                  // 목록 (카드) 모드
                  const displayColumns = currentTabConfig?.columns || [];
                  const summaryCount = currentTabConfig?.summaryColumnCount ?? 3;
                  const showLabel = currentTabConfig?.summaryShowLabel ?? true;

                  return (
                    <div className="space-y-2">
                      {currentTabData.map((item: any, idx: number) => {
                        const itemId = item.id ?? idx;
                        const isExpanded = expandedRightItems.has(itemId);

                        // 표시할 컬럼 결정
                        const columnsToShow =
                          displayColumns.length > 0
                            ? displayColumns
                            : Object.keys(item)
                                .filter(shouldShowField)
                                .slice(0, 8)
                                .map((key) => ({ name: key, label: key }));

                        const summaryColumns = columnsToShow.slice(0, summaryCount);
                        const detailColumns = columnsToShow.slice(summaryCount);

                        return (
                          <div key={`${itemId}-${idx}`} className="rounded-lg border bg-white p-3">
                            <div
                              className="flex cursor-pointer items-start justify-between"
                              onClick={() => toggleRightItemExpansion(itemId)}
                            >
                              <div className="flex-1">
                                <div className="flex flex-wrap gap-x-4 gap-y-1">
                                  {summaryColumns.map((col: any) => (
                                    <div key={col.name} className="text-sm">
                                      {showLabel && (
                                        <span className="text-muted-foreground mr-1">{col.label}:</span>
                                      )}
                                      <span className={col.bold ? "font-semibold" : ""}>
                                        {formatCellValue(col.name, item[col.name], {}, col.format)}
                                      </span>
                                    </div>
                                  ))}
                                </div>
                              </div>
                              <div className="ml-2 flex items-center gap-1">
                                {currentTabConfig?.showEdit && (
                                  <Button
                                    variant="ghost"
                                    size="sm"
                                    className="h-7 w-7 p-0"
                                    onClick={(e) => {
                                      e.stopPropagation();
                                      handleEditClick("right", item);
                                    }}
                                  >
                                    <Pencil className="h-3.5 w-3.5" />
                                  </Button>
                                )}
                                {currentTabConfig?.showDelete && (
                                  <Button
                                    variant="ghost"
                                    size="sm"
                                    className="h-7 w-7 p-0 text-destructive hover:text-destructive"
                                    onClick={(e) => {
                                      e.stopPropagation();
                                      handleDeleteClick("right", item);
                                    }}
                                  >
                                    <Trash2 className="h-3.5 w-3.5" />
                                  </Button>
                                )}
                                {detailColumns.length > 0 &&
                                  (isExpanded ? (
                                    <ChevronUp className="h-4 w-4 text-muted-foreground/70" />
                                  ) : (
                                    <ChevronDown className="h-4 w-4 text-muted-foreground/70" />
                                  ))}
                              </div>
                            </div>
                            {isExpanded && detailColumns.length > 0 && (
                              <div className="mt-2 border-t pt-2">
                                <div className="grid grid-cols-2 gap-2">
                                  {detailColumns.map((col: any) => (
                                    <div key={col.name} className="text-sm">
                                      <span className="text-muted-foreground">{col.label}:</span>
                                      <span className="ml-1">{formatCellValue(col.name, item[col.name], {}, col.format)}</span>
                                    </div>
                                  ))}
                                </div>
                              </div>
                            )}
                          </div>
                        );
                      })}
                    </div>
                  );
                }
              })()
            ) : (
              /* 기본 탭 (우측 패널) 데이터 */
              <>
                {isLoadingRight ? (
                  // 로딩 중
                  <div className="flex h-full items-center justify-center">
                    <div className="text-center">
                      <Loader2 className="text-primary mx-auto h-8 w-8 animate-spin" />
                      <p className="text-muted-foreground mt-2 text-sm">데이터를 불러오는 중...</p>
                    </div>
                  </div>
                ) : rightData ? (
                  // 실제 데이터 표시
                  Array.isArray(rightData) ? (
                    // 조인 모드: 여러 데이터를 테이블/리스트로 표시
                    (() => {
                  // 검색 필터링
                  const filteredData = rightSearchQuery
                    ? rightData.filter((item) => {
                        const searchLower = rightSearchQuery.toLowerCase();
                        return Object.entries(item).some(([key, value]) => {
                          if (value === null || value === undefined) return false;
                          return String(value).toLowerCase().includes(searchLower);
                        });
                      })
                    : rightData;

                  // 테이블 모드 체크
                  const isTableMode = componentConfig.rightPanel?.displayMode === "table";

                  if (isTableMode) {
                    // 테이블 모드 렌더링
                    const displayColumns = componentConfig.rightPanel?.columns || [];

                    // 🆕 그룹 합산 모드일 때: 복합키 컬럼을 우선 표시
                    const relationKeys = componentConfig.rightPanel?.relation?.keys || [];
                    const keyColumns = relationKeys.map((k: any) => k.leftColumn).filter(Boolean);
                    const isGroupedMode = selectedLeftItem?._originalItems?.length > 0;

                    let columnsToShow: any[] = [];

                    if (displayColumns.length > 0) {
                      // 설정된 컬럼 사용
                      columnsToShow = displayColumns.map((col) => ({
                        ...col,
                        label: rightColumnLabels[col.name] || col.label || col.name,
                        format: col.format,
                      }));

                      // 🆕 그룹 합산 모드이고, 키 컬럼이 표시 목록에 없으면 맨 앞에 추가
                      if (isGroupedMode && keyColumns.length > 0) {
                        const existingColNames = columnsToShow.map((c) => c.name);
                        const missingKeyColumns = keyColumns.filter((k: string) => !existingColNames.includes(k));

                        if (missingKeyColumns.length > 0) {
                          const keyColsToAdd = missingKeyColumns.map((colName: string) => ({
                            name: colName,
                            label: rightColumnLabels[colName] || colName,
                            width: 120,
                            align: "left" as const,
                            format: undefined,
                            _isKeyColumn: true, // 구분용 플래그
                          }));
                          columnsToShow = [...keyColsToAdd, ...columnsToShow];
                          console.log("🔗 [우측패널] 그룹모드 - 키 컬럼 추가:", missingKeyColumns);
                        }
                      }
                    } else {
                      // 기본 컬럼 자동 생성
                      columnsToShow = Object.keys(filteredData[0] || {})
                        .filter((key) => shouldShowField(key))
                        .slice(0, 5)
                        .map((key) => ({
                          name: key,
                          label: rightColumnLabels[key] || key,
                          width: 150,
                          align: "left" as const,
                          format: undefined,
                        }));
                    }

                    return (
                      <div className="w-full">
                        <div className="text-muted-foreground mb-2 text-xs">
                          {filteredData.length}개의 관련 데이터
                          {rightSearchQuery && filteredData.length !== rightData.length && (
                            <span className="text-primary ml-1">(전체 {rightData.length}개 중)</span>
                          )}
                        </div>
                        <div className="overflow-auto">
                          <table className="min-w-full divide-y divide-border">
                            <thead className="sticky top-0 z-10 bg-muted">
                              <tr>
                                {columnsToShow.map((col, idx) => (
                                  <th
                                    key={idx}
                                    className="px-3 py-2 text-left text-xs font-medium tracking-wider text-muted-foreground uppercase"
                                    style={{
                                      width: col.width ? `${col.width}px` : "auto",
                                      textAlign: col.align || "left",
                                    }}
                                  >
                                    {col.label}
                                  </th>
                                ))}
                                {/* 수정 또는 삭제 버튼이 하나라도 활성화되어 있을 때만 작업 컬럼 표시 */}
                                {!isDesignMode &&
                                  ((componentConfig.rightPanel?.editButton?.enabled ?? true) ||
                                    (componentConfig.rightPanel?.deleteButton?.enabled ?? true)) && (
                                    <th className="px-3 py-2 text-right text-xs font-medium text-muted-foreground uppercase">
                                      작업
                                    </th>
                                  )}
                              </tr>
                            </thead>
                            <tbody className="divide-y divide-border bg-white">
                              {filteredData.map((item, idx) => {
                                const itemId = item.id || item.ID;

                                return (
                                  <tr key={itemId != null ? `${itemId}-${idx}` : idx} className="hover:bg-accent transition-colors">
                                    {columnsToShow.map((col, colIdx) => (
                                      <td
                                        key={colIdx}
                                        className="px-3 py-2 text-sm whitespace-nowrap text-foreground"
                                        style={{ textAlign: col.align || "left", overflow: "hidden", textOverflow: "ellipsis" }}
                                      >
                                        {formatCellValue(
                                          col.name,
                                          getEntityJoinValue(item, col.name),
                                          rightCategoryMappings,
                                          col.format,
                                        )}
                                      </td>
                                    ))}
                                    {/* 수정 또는 삭제 버튼이 하나라도 활성화되어 있을 때만 작업 셀 표시 */}
                                    {!isDesignMode &&
                                      ((componentConfig.rightPanel?.editButton?.enabled ?? true) ||
                                        (componentConfig.rightPanel?.deleteButton?.enabled ?? true)) && (
                                        <td className="px-3 py-2 text-right text-sm whitespace-nowrap">
                                          <div className="flex justify-end gap-1">
                                            {(componentConfig.rightPanel?.editButton?.enabled ?? true) && (
                                              <Button
                                                variant={
                                                  componentConfig.rightPanel?.editButton?.buttonVariant || "outline"
                                                }
                                                size="sm"
                                                onClick={(e) => {
                                                  e.stopPropagation();
                                                  handleEditClick("right", item);
                                                }}
                                                className="h-7"
                                              >
                                                <Pencil className="mr-1 h-3 w-3" />
                                                {componentConfig.rightPanel?.editButton?.buttonLabel || "수정"}
                                              </Button>
                                            )}
                                            {(componentConfig.rightPanel?.deleteButton?.enabled ?? true) && (
                                              <button
                                                onClick={(e) => {
                                                  e.stopPropagation();
                                                  handleDeleteClick("right", item);
                                                }}
                                                className="rounded p-1 transition-colors hover:bg-destructive/10"
                                                title={componentConfig.rightPanel?.deleteButton?.buttonLabel || "삭제"}
                                              >
                                                <Trash2 className="h-4 w-4 text-destructive" />
                                              </button>
                                            )}
                                          </div>
                                        </td>
                                      )}
                                  </tr>
                                );
                              })}
                            </tbody>
                          </table>
                        </div>
                      </div>
                    );
                  }

                  // 목록 모드 (기존)
                  return filteredData.length > 0 ? (
                    <div className="space-y-2">
                      <div className="text-muted-foreground mb-2 text-xs">
                        {filteredData.length}개의 관련 데이터
                        {rightSearchQuery && filteredData.length !== rightData.length && (
                          <span className="text-primary ml-1">(전체 {rightData.length}개 중)</span>
                        )}
                      </div>
                      {filteredData.map((item, index) => {
                        const itemId = item.id || item.ID || index;
                        const isExpanded = expandedRightItems.has(itemId);

                        // 우측 패널 표시 컬럼 설정 확인
                        const rightColumns = componentConfig.rightPanel?.columns;
                        let firstValues: [string, any, string][] = [];
                        let allValues: [string, any, string][] = [];

                        if (rightColumns && rightColumns.length > 0) {
                          // 설정된 컬럼만 표시 (엔티티 조인 컬럼 처리)
                          const summaryCount = componentConfig.rightPanel?.summaryColumnCount ?? 3;
                          firstValues = rightColumns
                            .slice(0, summaryCount)
                            .map((col) => {
                              // 🆕 엔티티 조인 컬럼 처리 (getEntityJoinValue 사용)
                              const value = getEntityJoinValue(item, col.name);
                              return [col.name, value, col.label] as [string, any, string];
                            })
                            .filter(([_, value]) => value !== null && value !== undefined && value !== "");

                          allValues = rightColumns
                            .map((col) => {
                              // 🆕 엔티티 조인 컬럼 처리 (getEntityJoinValue 사용)
                              const value = getEntityJoinValue(item, col.name);
                              return [col.name, value, col.label] as [string, any, string];
                            })
                            .filter(([_, value]) => value !== null && value !== undefined && value !== "");
                        } else {
                          // 설정 없으면 모든 컬럼 표시 (기존 로직)
                          const summaryCount = componentConfig.rightPanel?.summaryColumnCount ?? 3;
                          firstValues = Object.entries(item)
                            .filter(([key]) => !key.toLowerCase().includes("id"))
                            .slice(0, summaryCount)
                            .map(([key, value]) => [key, value, ""] as [string, any, string]);

                          allValues = Object.entries(item)
                            .filter(([key, value]) => value !== null && value !== undefined && value !== "")
                            .map(([key, value]) => [key, value, ""] as [string, any, string]);
                        }

                        return (
                          <div
                            key={`${itemId}-${index}`}
                            className="bg-card overflow-hidden rounded-lg border shadow-sm transition-all hover:shadow-md"
                          >
                            {/* 요약 정보 */}
                            <div className="p-3">
                              <div className="flex items-start justify-between gap-2">
                                <div
                                  className="min-w-0 flex-1 cursor-pointer"
                                  onClick={() => toggleRightItemExpansion(itemId)}
                                >
                                  <div className="flex flex-wrap items-center gap-x-4 gap-y-2">
                                    {firstValues.map(([key, value, label], idx) => {
                                      // 포맷 설정 및 볼드 설정 찾기
                                      const colConfig = rightColumns?.find((c) => c.name === key);
                                      const format = colConfig?.format;
                                      const boldValue = colConfig?.bold ?? false;

                                      // 🆕 포맷 적용 (날짜/숫자/카테고리)
                                      const displayValue = formatCellValue(key, value, rightCategoryMappings, format);

                                      const showLabel = componentConfig.rightPanel?.summaryShowLabel ?? true;

                                      return (
                                        <div key={key} className="flex items-baseline gap-1">
                                          {showLabel && (
                                            <span className="text-muted-foreground text-xs font-medium whitespace-nowrap">
                                              {label || getColumnLabel(key)}:
                                            </span>
                                          )}
                                          <span
                                            className={`text-foreground text-sm ${boldValue ? "font-semibold" : ""}`}
                                          >
                                            {displayValue}
                                          </span>
                                        </div>
                                      );
                                    })}
                                  </div>
                                </div>
                                <div className="flex flex-shrink-0 items-start gap-1 pt-1">
                                  {/* 수정 버튼 */}
                                  {!isDesignMode && (componentConfig.rightPanel?.editButton?.enabled ?? true) && (
                                    <Button
                                      variant={componentConfig.rightPanel?.editButton?.buttonVariant || "outline"}
                                      size="sm"
                                      onClick={(e) => {
                                        e.stopPropagation();
                                        handleEditClick("right", item);
                                      }}
                                      className="h-7"
                                    >
                                      <Pencil className="mr-1 h-3 w-3" />
                                      {componentConfig.rightPanel?.editButton?.buttonLabel || "수정"}
                                    </Button>
                                  )}
                                  {/* 삭제 버튼 */}
                                  {!isDesignMode && (componentConfig.rightPanel?.deleteButton?.enabled ?? true) && (
                                    <button
                                      onClick={(e) => {
                                        e.stopPropagation();
                                        handleDeleteClick("right", item);
                                      }}
                                      className="rounded p-1 transition-colors hover:bg-destructive/10"
                                      title={componentConfig.rightPanel?.deleteButton?.buttonLabel || "삭제"}
                                    >
                                      <Trash2 className="h-4 w-4 text-destructive" />
                                    </button>
                                  )}
                                  {/* 확장/접기 버튼 */}
                                  <button
                                    onClick={() => toggleRightItemExpansion(itemId)}
                                    className="rounded p-1 transition-colors hover:bg-muted/80"
                                  >
                                    {isExpanded ? (
                                      <ChevronUp className="text-muted-foreground h-5 w-5" />
                                    ) : (
                                      <ChevronDown className="text-muted-foreground h-5 w-5" />
                                    )}
                                  </button>
                                </div>
                              </div>
                            </div>

                            {/* 상세 정보 (확장 시 표시) */}
                            {isExpanded && (
                              <div className="bg-muted/50 border-t px-3 py-2">
                                <div className="mb-2 text-xs font-semibold">전체 상세 정보</div>
                                <div className="bg-card overflow-auto rounded-md border">
                                  <table className="w-full text-sm">
                                    <tbody className="divide-border divide-y">
                                      {allValues.map(([key, value, label]) => {
                                        // 포맷 설정 찾기
                                        const colConfig = rightColumns?.find((c) => c.name === key);
                                        const format = colConfig?.format;

                                        // 🆕 포맷 적용 (날짜/숫자/카테고리)
                                        const displayValue = formatCellValue(key, value, rightCategoryMappings, format);

                                        return (
                                          <tr key={key} className="hover:bg-muted">
                                            <td className="text-muted-foreground px-3 py-2 font-medium whitespace-nowrap">
                                              {label || getColumnLabel(key)}
                                            </td>
                                            <td className="text-foreground px-3 py-2 break-all">{displayValue}</td>
                                          </tr>
                                        );
                                      })}
                                    </tbody>
                                  </table>
                                </div>
                              </div>
                            )}
                          </div>
                        );
                      })}
                    </div>
                  ) : (
                    <div className="text-muted-foreground py-8 text-center text-sm">
                      {rightSearchQuery ? (
                        <>
                          <p>검색 결과가 없습니다.</p>
                          <p className="text-muted-foreground/70 mt-1 text-xs">다른 검색어를 입력해보세요.</p>
                        </>
                      ) : (
                        "관련 데이터가 없습니다."
                      )}
                    </div>
                  );
                })()
              ) : (
                // 상세 모드: 단일 객체를 상세 정보로 표시
                (() => {
                  const rightColumns = componentConfig.rightPanel?.columns;
                  let displayEntries: [string, any, string][] = [];

                  if (rightColumns && rightColumns.length > 0) {
                    console.log("🔍 [디버깅] 상세 모드 표시 로직:");
                    console.log("  📋 rightData 전체:", rightData);
                    console.log("  📋 rightData keys:", Object.keys(rightData));
                    console.log(
                      "  ⚙️ 설정된 컬럼:",
                      rightColumns.map((c) => `${c.name} (${c.label})`),
                    );

                    // 설정된 컬럼만 표시
                    displayEntries = rightColumns
                      .map((col) => {
                        // 🆕 엔티티 조인 컬럼 처리 (예: item_info.item_name → item_name)
                        let value = rightData[col.name];
                        console.log(`  🔎 컬럼 "${col.name}": 직접 접근 = ${value}`);

                        if (value === undefined && col.name.includes(".")) {
                          const columnName = col.name.split(".").pop();
                          value = rightData[columnName || ""];
                          console.log(`    → 변환 후 "${columnName}" 접근 = ${value}`);
                        }

                        return [col.name, value, col.label] as [string, any, string];
                      })
                      .filter(([key, value]) => {
                        const filtered = value === null || value === undefined || value === "";
                        if (filtered) {
                          console.log(`  ❌ 필터링됨: "${key}" (값: ${value})`);
                        }
                        return !filtered;
                      });

                    console.log("  ✅ 최종 표시할 항목:", displayEntries.length, "개");
                  } else {
                    // 설정 없으면 모든 컬럼 표시
                    displayEntries = Object.entries(rightData)
                      .filter(([_, value]) => value !== null && value !== undefined && value !== "")
                      .map(([key, value]) => [key, value, ""] as [string, any, string]);
                    console.log("  ⚠️ 컬럼 설정 없음, 모든 컬럼 표시");
                  }

                  return (
                    <div className="space-y-2">
                      {displayEntries.map(([key, value, label]) => (
                        <div key={key} className="bg-card rounded-lg border p-4 shadow-sm">
                          <div className="text-muted-foreground mb-1 text-xs font-semibold tracking-wide uppercase">
                            {label || getColumnLabel(key)}
                          </div>
                          <div className="text-sm">{String(value)}</div>
                        </div>
                      ))}
                    </div>
                  );
                })()
              )
            ) : selectedLeftItem && isDesignMode ? (
              // 디자인 모드: 샘플 데이터
              <div className="space-y-4">
                <div className="rounded-lg border p-4">
                  <h3 className="mb-2 font-medium">{selectedLeftItem.name} 상세 정보</h3>
                  <div className="space-y-2 text-sm">
                    <div className="flex justify-between">
                      <span className="text-muted-foreground">항목 1:</span>
                      <span className="font-medium">값 1</span>
                    </div>
                    <div className="flex justify-between">
                      <span className="text-muted-foreground">항목 2:</span>
                      <span className="font-medium">값 2</span>
                    </div>
                    <div className="flex justify-between">
                      <span className="text-muted-foreground">항목 3:</span>
                      <span className="font-medium">값 3</span>
                    </div>
                  </div>
                </div>
              </div>
                ) : (
                  // 선택 없음
                  <div className="flex h-full items-center justify-center">
                    <div className="text-muted-foreground text-center text-sm">
                      <p className="mb-2">좌측에서 항목을 선택하세요</p>
                      <p className="text-xs">선택한 항목의 상세 정보가 여기에 표시됩니다</p>
                    </div>
                  </div>
                )}
              </>
            )}
          </CardContent>
        </Card>
      </div>

      {/* 추가 모달 */}
      <Dialog open={showAddModal} onOpenChange={setShowAddModal}>
        <DialogContent className="max-w-[95vw] sm:max-w-[500px]">
          <DialogHeader>
            <DialogTitle className="text-base sm:text-lg">
              {addModalPanel === "left"
                ? `${componentConfig.leftPanel?.title} 추가`
                : addModalPanel === "right"
                  ? `${componentConfig.rightPanel?.title} 추가`
                  : `하위 ${componentConfig.leftPanel?.title} 추가`}
            </DialogTitle>
            <DialogDescription className="text-xs sm:text-sm">
              {addModalPanel === "left-item"
                ? "선택한 항목의 하위 항목을 추가합니다. 필수 항목을 입력해주세요."
                : "새로운 데이터를 추가합니다. 필수 항목을 입력해주세요."}
            </DialogDescription>
          </DialogHeader>

          <div className="space-y-3 sm:space-y-4">
            {(() => {
              // 어떤 컬럼들을 표시할지 결정
              let modalColumns: Array<{ name: string; label: string; required?: boolean }> | undefined;

              if (addModalPanel === "left") {
                modalColumns = componentConfig.leftPanel?.addModalColumns;
              } else if (addModalPanel === "right") {
                modalColumns = componentConfig.rightPanel?.addModalColumns;
              } else if (addModalPanel === "left-item") {
                modalColumns = componentConfig.leftPanel?.itemAddConfig?.addModalColumns;
              }

              return modalColumns?.map((col, index) => {
                // 항목별 추가 버튼으로 열렸을 때, parentColumn은 미리 채워져 있고 수정 불가
                const isItemAddPreFilled =
                  addModalPanel === "left-item" &&
                  componentConfig.leftPanel?.itemAddConfig?.parentColumn === col.name &&
                  addModalFormData[col.name];

                // 우측 패널 추가 시, 조인 컬럼(rightColumn)은 미리 채워져 있고 수정 불가
                const isRightJoinPreFilled =
                  addModalPanel === "right" &&
                  componentConfig.rightPanel?.rightColumn === col.name &&
                  addModalFormData[col.name];

                const isPreFilled = isItemAddPreFilled || isRightJoinPreFilled;

                return (
                  <div key={index}>
                    <Label htmlFor={col.name} className="text-xs sm:text-sm">
                      {col.label} {col.required && <span className="text-destructive">*</span>}
                      {isPreFilled && <span className="ml-2 text-[10px] text-primary">(자동 설정됨)</span>}
                    </Label>
                    <Input
                      id={col.name}
                      value={addModalFormData[col.name] || ""}
                      onChange={(e) => {
                        setAddModalFormData((prev) => ({
                          ...prev,
                          [col.name]: e.target.value,
                        }));
                      }}
                      placeholder={`${col.label} 입력`}
                      className="h-8 text-xs sm:h-10 sm:text-sm"
                      required={col.required}
                      disabled={isPreFilled}
                    />
                  </div>
                );
              });
            })()}
          </div>

          <DialogFooter className="gap-2 sm:gap-0">
            <Button
              variant="outline"
              onClick={() => setShowAddModal(false)}
              className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
            >
              취소
            </Button>
            <Button onClick={handleAddModalSave} className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm">
              <Save className="mr-1 h-3 w-3 sm:h-4 sm:w-4" />
              저장
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* 수정 모달 */}
      <Dialog open={showEditModal} onOpenChange={setShowEditModal}>
        <DialogContent className="max-w-[95vw] sm:max-w-[500px]">
          <DialogHeader>
            <DialogTitle className="text-base sm:text-lg">
              {editModalPanel === "left"
                ? `${componentConfig.leftPanel?.title} 수정`
                : `${componentConfig.rightPanel?.title} 수정`}
            </DialogTitle>
            <DialogDescription className="text-xs sm:text-sm">
              데이터를 수정합니다. 필요한 항목을 변경해주세요.
            </DialogDescription>
          </DialogHeader>

          <div className="space-y-3 sm:space-y-4">
            {editModalItem &&
              (() => {
                // 좌측 패널 수정: leftColumn만 수정 가능
                if (editModalPanel === "left") {
                  const leftColumn = componentConfig.rightPanel?.relation?.leftColumn;

                  // leftColumn만 표시
                  if (!leftColumn || editModalFormData[leftColumn] === undefined) {
                    return <p className="text-muted-foreground text-sm">수정 가능한 컬럼이 없습니다.</p>;
                  }

                  return (
                    <div>
                      <Label htmlFor={`edit-${leftColumn}`} className="text-xs sm:text-sm">
                        {leftColumn}
                      </Label>
                      <Input
                        id={`edit-${leftColumn}`}
                        value={editModalFormData[leftColumn] || ""}
                        onChange={(e) => {
                          setEditModalFormData((prev) => ({
                            ...prev,
                            [leftColumn]: e.target.value,
                          }));
                        }}
                        placeholder={`${leftColumn} 입력`}
                        className="h-8 text-xs sm:h-10 sm:text-sm"
                      />
                    </div>
                  );
                }

                // 우측 패널 수정: 우측 패널에 설정된 표시 컬럼들만
                if (editModalPanel === "right") {
                  const rightColumns = componentConfig.rightPanel?.columns;

                  if (rightColumns && rightColumns.length > 0) {
                    // 설정된 컬럼만 표시
                    return rightColumns.map((col) => (
                      <div key={col.name}>
                        <Label htmlFor={`edit-${col.name}`} className="text-xs sm:text-sm">
                          {col.label || col.name}
                        </Label>
                        <Input
                          id={`edit-${col.name}`}
                          value={editModalFormData[col.name] || ""}
                          onChange={(e) => {
                            setEditModalFormData((prev) => ({
                              ...prev,
                              [col.name]: e.target.value,
                            }));
                          }}
                          placeholder={`${col.label || col.name} 입력`}
                          className="h-8 text-xs sm:h-10 sm:text-sm"
                        />
                      </div>
                    ));
                  } else {
                    // 설정이 없으면 모든 컬럼 표시 (민감한 필드 제외)
                    return Object.entries(editModalFormData)
                      .filter(([key]) => shouldShowField(key))
                      .map(([key, value]) => (
                        <div key={key}>
                          <Label htmlFor={`edit-${key}`} className="text-xs sm:text-sm">
                            {key}
                          </Label>
                          <Input
                            id={`edit-${key}`}
                            value={editModalFormData[key] || ""}
                            onChange={(e) => {
                              setEditModalFormData((prev) => ({
                                ...prev,
                                [key]: e.target.value,
                              }));
                            }}
                            placeholder={`${key} 입력`}
                            className="h-8 text-xs sm:h-10 sm:text-sm"
                          />
                        </div>
                      ));
                  }
                }

                return null;
              })()}
          </div>

          <DialogFooter className="gap-2 sm:gap-0">
            <Button
              variant="outline"
              onClick={() => setShowEditModal(false)}
              className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
            >
              취소
            </Button>
            <Button onClick={handleEditModalSave} className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm">
              <Save className="mr-1 h-3 w-3 sm:h-4 sm:w-4" />
              저장
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* 삭제 확인 모달 */}
      <Dialog open={showDeleteModal} onOpenChange={setShowDeleteModal}>
        <DialogContent className="max-w-[95vw] sm:max-w-[500px]">
          <DialogHeader>
            <DialogTitle className="text-base sm:text-lg">삭제 확인</DialogTitle>
            <DialogDescription className="text-xs sm:text-sm">
              정말로 이 데이터를 삭제하시겠습니까?
              <br />이 작업은 되돌릴 수 없습니다.
            </DialogDescription>
          </DialogHeader>

          <DialogFooter className="gap-2 sm:gap-0">
            <Button
              variant="outline"
              onClick={() => setShowDeleteModal(false)}
              className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
            >
              취소
            </Button>
            <Button
              variant="destructive"
              onClick={handleDeleteConfirm}
              className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
            >
              <Trash2 className="mr-1 h-3 w-3 sm:h-4 sm:w-4" />
              삭제
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
};

/**
 * SplitPanelLayout 래퍼 컴포넌트
 */
export const SplitPanelLayoutWrapper: React.FC<SplitPanelLayoutComponentProps> = (props) => {
  return <SplitPanelLayoutComponent {...props} />;
};
