"use client";

import { useState, useCallback, useEffect, useMemo, useRef } from "react";

import {
  Group,
  Database,
  Trash2,
  Copy,
  Clipboard,
} from "lucide-react";
import {
  ScreenDefinition,
  ComponentData,
  LayoutData,
  GroupState,
  WebType,
  TableInfo,
  GroupComponent,
  Position,
} from "@/types/screen";
import { generateComponentId } from "@/lib/utils/generateId";
import {
  createGroupComponent,
  calculateBoundingBox,
  calculateRelativePositions,
  restoreAbsolutePositions,
  getGroupChildren,
} from "@/lib/utils/groupingUtils";
import {
  calculateGridInfo,
  snapToGrid,
  snapSizeToGrid,
  generateGridLines,
  GridSettings as GridUtilSettings,
} from "@/lib/utils/gridUtils";
import { GroupingToolbar } from "./GroupingToolbar";
import { screenApi } from "@/lib/api/screen";
import { toast } from "sonner";

import StyleEditor from "./StyleEditor";
import { RealtimePreview } from "./RealtimePreview";
import FloatingPanel from "./FloatingPanel";
import DesignerToolbar from "./DesignerToolbar";
import TablesPanel from "./panels/TablesPanel";
import PropertiesPanel from "./panels/PropertiesPanel";
import GridPanel from "./panels/GridPanel";
import { usePanelState, PanelConfig } from "@/hooks/usePanelState";

interface ScreenDesignerProps {
  selectedScreen: ScreenDefinition | null;
  onBackToList: () => void;
}

// 패널 설정
const panelConfigs: PanelConfig[] = [
  {
    id: "tables",
    title: "테이블 목록",
    defaultPosition: "left",
    defaultWidth: 320,
    defaultHeight: 600,
    shortcutKey: "t",
  },
  {
    id: "properties",
    title: "속성 편집",
    defaultPosition: "right",
    defaultWidth: 320,
    defaultHeight: 500,
    shortcutKey: "p",
  },
  {
    id: "styles",
    title: "스타일 편집",
    defaultPosition: "right",
    defaultWidth: 320,
    defaultHeight: 400,
    shortcutKey: "s",
  },
  {
    id: "grid",
    title: "격자 설정",
    defaultPosition: "right",
    defaultWidth: 280,
    defaultHeight: 450,
    shortcutKey: "g",
  },
];

export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenDesignerProps) {
  // 패널 상태 관리
  const {
    panelStates,
    togglePanel,
    openPanel,
    closePanel,
    closeAllPanels,
  } = usePanelState(panelConfigs);

  const [layout, setLayout] = useState<LayoutData>({
    components: [],
    gridSettings: { columns: 12, gap: 16, padding: 16, snapToGrid: true, showGrid: true },
  });
  const [isSaving, setIsSaving] = useState(false);
  const [isLoading, setIsLoading] = useState(false);
  const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
  const [selectedComponent, setSelectedComponent] = useState<ComponentData | null>(null);

  // 실행취소/다시실행을 위한 히스토리 상태
  const [history, setHistory] = useState<LayoutData[]>([
    {
      components: [],
      gridSettings: { columns: 12, gap: 16, padding: 16, snapToGrid: true },
    },
  ]);
  const [historyIndex, setHistoryIndex] = useState(0);

  // 클립보드 상태 (복사/붙여넣기용)
  const [clipboard, setClipboard] = useState<{
    type: "single" | "multiple" | "group";
    data: ComponentData[];
    offset: { x: number; y: number };
    boundingBox?: { x: number; y: number; width: number; height: number };
  } | null>(null);

  // 히스토리에 상태 저장
  const saveToHistory = useCallback(
    (newLayout: LayoutData) => {
      setHistory((prevHistory) => {
        const newHistory = prevHistory.slice(0, historyIndex + 1);
        newHistory.push(JSON.parse(JSON.stringify(newLayout))); // 깊은 복사
        return newHistory.slice(-50); // 최대 50개 히스토리 유지
      });
      setHistoryIndex((prevIndex) => Math.min(prevIndex + 1, 49));
      setHasUnsavedChanges(true); // 변경사항 표시
    },
    [historyIndex],
  );

  // 실행취소
  const undo = useCallback(() => {
    if (historyIndex > 0) {
      const newIndex = historyIndex - 1;
      setHistoryIndex(newIndex);
      setLayout(JSON.parse(JSON.stringify(history[newIndex])));
      setSelectedComponent(null); // 선택 해제
    }
  }, [historyIndex, history]);

  // 다시실행
  const redo = useCallback(() => {
    if (historyIndex < history.length - 1) {
      const newIndex = historyIndex + 1;
      setHistoryIndex(newIndex);
      setLayout(JSON.parse(JSON.stringify(history[newIndex])));
      setSelectedComponent(null); // 선택 해제
    }
  }, [historyIndex, history]);

  const [dragState, setDragState] = useState({
    isDragging: false,
    draggedComponent: null as ComponentData | null,
    draggedComponents: [] as ComponentData[], // 다중선택된 컴포넌트들
    originalPosition: { x: 0, y: 0 },
    currentPosition: { x: 0, y: 0 },
    isMultiDrag: false, // 다중 드래그 여부
    initialMouse: { x: 0, y: 0 },
    grabOffset: { x: 0, y: 0 },
  });
  const [groupState, setGroupState] = useState<GroupState>({
    isGrouping: false,
    selectedComponents: [],
    groupTarget: null,
    groupMode: "create",
  });

  // 그룹 생성 다이얼로그 상태
  const [showGroupCreateDialog, setShowGroupCreateDialog] = useState(false);

  // 캔버스 컨테이너 참조
  const canvasRef = useRef<HTMLDivElement>(null);

  // 격자 정보 계산
  const gridInfo = useMemo(() => {
    if (!layout.gridSettings) return null;

    // canvasRef가 없거나 크기가 0인 경우 기본값 사용
    let width = 800;
    let height = 600;

    if (canvasRef.current) {
      const rect = canvasRef.current.getBoundingClientRect();
      width = Math.max(rect.width || 800, 800);
      height = Math.max(rect.height || 600, 600);
    }

    return calculateGridInfo(width, height, layout.gridSettings as GridUtilSettings);
  }, [layout.gridSettings]);

  // 격자 설정 변경 핸들러
  const handleGridSettingsChange = useCallback(
    (newGridSettings: GridUtilSettings) => {
      let updatedComponents = layout.components;

      // 격자 스냅이 활성화되어 있고 격자 정보가 있으며 컴포넌트가 있는 경우 기존 컴포넌트들을 새 격자에 맞춤
      if (newGridSettings.snapToGrid && gridInfo && layout.components.length > 0) {
        // 현재 캔버스 크기 가져오기
        let canvasWidth = 800;
        let canvasHeight = 600;

        if (canvasRef.current) {
          const rect = canvasRef.current.getBoundingClientRect();
          canvasWidth = Math.max(rect.width || 800, 800);
          canvasHeight = Math.max(rect.height || 600, 600);
        }

        const newGridInfo = calculateGridInfo(canvasWidth, canvasHeight, newGridSettings);

        updatedComponents = layout.components.map((comp) => {
          // 그룹의 자식 컴포넌트는 건드리지 않음 (그룹에서 처리)
          if (comp.parentId) return comp;

          // 기존 격자에서의 상대적 위치 계산 (격자 컬럼 단위)
          const oldGridInfo = gridInfo;
          const oldColumnWidth = oldGridInfo.columnWidth;
          const oldGap = layout.gridSettings?.gap || 16;
          const oldPadding = layout.gridSettings?.padding || 16;

          // 기존 위치를 격자 컬럼/행 단위로 변환
          const oldGridX = Math.round((comp.position.x - oldPadding) / (oldColumnWidth + oldGap));
          const oldGridY = Math.round((comp.position.y - oldPadding) / 20); // 20px 단위

          // 기존 크기를 격자 컬럼 단위로 변환
          const oldGridColumns = Math.max(1, Math.round((comp.size.width + oldGap) / (oldColumnWidth + oldGap)));
          const oldGridRows = Math.max(2, Math.round(comp.size.height / 20)); // 20px 단위

          // 새 격자에서의 위치와 크기 계산
          const newColumnWidth = newGridInfo.columnWidth;
          const newGap = newGridSettings.gap;
          const newPadding = newGridSettings.padding;

          // 새 위치 계산 (격자 비율 유지)
          const newX = newPadding + oldGridX * (newColumnWidth + newGap);
          const newY = newPadding + oldGridY * 20;

          // 새 크기 계산 (격자 비율 유지)
          const newWidth = oldGridColumns * newColumnWidth + (oldGridColumns - 1) * newGap;
          const newHeight = oldGridRows * 20;

          return {
            ...comp,
            position: { x: newX, y: newY, z: comp.position.z || 1 },
            size: { width: newWidth, height: newHeight },
          };
        });
      }

      const newLayout = {
        ...layout,
        components: updatedComponents,
        gridSettings: newGridSettings,
      };
      setLayout(newLayout);
      saveToHistory(newLayout);
    },
    [layout, saveToHistory, gridInfo],
  );

  const [tables, setTables] = useState<TableInfo[]>([]);
  const [expandedTables, setExpandedTables] = useState<Set<string>>(new Set());

  // 테이블 검색 및 페이징 상태 추가
  const [searchTerm, setSearchTerm] = useState("");
  const [currentPage, setCurrentPage] = useState(1);
  const [itemsPerPage] = useState(10);

  // 드래그 박스(마키) 다중선택 상태
  const [selectionState, setSelectionState] = useState({
    isSelecting: false,
    start: { x: 0, y: 0 },
    current: { x: 0, y: 0 },
  });

  // 선택된 컴포넌트를 항상 레이아웃 최신 값으로 참조 (좌표 실시간 반영용)
  const selectedFromLayout = useMemo(() => {
    if (!selectedComponent) return null;
    return layout.components.find((c) => c.id === selectedComponent.id) || null;
  }, [selectedComponent, layout.components]);

  // 드래그 중에는 라이브 좌표를 계산하여 속성 패널에 표시
  const liveSelectedPosition = useMemo(() => {
    if (!selectedFromLayout) return { x: 0, y: 0 };

    let x = selectedFromLayout.position.x;
    let y = selectedFromLayout.position.y;

    if (dragState.isDragging) {
      const isSelectedInMulti = groupState.selectedComponents.includes(selectedFromLayout.id);
      if (dragState.isMultiDrag && isSelectedInMulti) {
        const deltaX = dragState.currentPosition.x - dragState.initialMouse.x;
        const deltaY = dragState.currentPosition.y - dragState.initialMouse.y;
        x = selectedFromLayout.position.x + deltaX;
        y = selectedFromLayout.position.y + deltaY;
      } else if (dragState.draggedComponent?.id === selectedFromLayout.id) {
        x = dragState.currentPosition.x - dragState.grabOffset.x;
        y = dragState.currentPosition.y - dragState.grabOffset.y;
      }
    }

    return { x: Math.round(x), y: Math.round(y) };
  }, [
    selectedFromLayout,
    dragState.isDragging,
    dragState.isMultiDrag,
    dragState.currentPosition.x,
    dragState.currentPosition.y,
    dragState.initialMouse.x,
    dragState.initialMouse.y,
    dragState.grabOffset.x,
    dragState.grabOffset.y,
    groupState.selectedComponents,
  ]);

  // 컴포넌트의 절대 좌표 계산 (그룹 자식은 부모 오프셋을 누적)
  const getAbsolutePosition = useCallback(
    (comp: ComponentData) => {
      let x = comp.position.x;
      let y = comp.position.y;
      let cur: ComponentData | undefined = comp;
      while (cur.parentId) {
        const parent = layout.components.find((c) => c.id === cur!.parentId);
        if (!parent) break;
        x += parent.position.x;
        y += parent.position.y;
        cur = parent;
      }
      return { x, y };
    },
    [layout.components],
  );

  // 마키 선택 시작 (캔버스 빈 영역 마우스다운)
  const handleMarqueeStart = useCallback(
    (e: React.MouseEvent) => {
      if (dragState.isDragging) return; // 드래그 중이면 무시
      const rect = canvasRef.current?.getBoundingClientRect();
      const scrollLeft = scrollContainerRef.current?.scrollLeft || 0;
      const scrollTop = scrollContainerRef.current?.scrollTop || 0;
      const x = rect ? e.clientX - rect.left + scrollLeft : 0;
      const y = rect ? e.clientY - rect.top + scrollTop : 0;
      setSelectionState({ isSelecting: true, start: { x, y }, current: { x, y } });
      // 기존 선택 초기화 (Shift 미사용 시)
      if (!e.shiftKey) {
        setGroupState((prev) => ({ ...prev, selectedComponents: [] }));
      }
    },
    [dragState.isDragging],
  );

  // 마키 이동
  const handleMarqueeMove = useCallback(
    (e: React.MouseEvent) => {
      if (!selectionState.isSelecting) return;
      const rect = canvasRef.current?.getBoundingClientRect();
      const scrollLeft = scrollContainerRef.current?.scrollLeft || 0;
      const scrollTop = scrollContainerRef.current?.scrollTop || 0;
      const x = rect ? e.clientX - rect.left + scrollLeft : 0;
      const y = rect ? e.clientY - rect.top + scrollTop : 0;
      setSelectionState((prev) => ({ ...prev, current: { x, y } }));
    },
    [selectionState.isSelecting],
  );

  // 마키 종료 -> 영역 내 컴포넌트 선택
  const handleMarqueeEnd = useCallback(() => {
    if (!selectionState.isSelecting) return;
    const minX = Math.min(selectionState.start.x, selectionState.current.x);
    const minY = Math.min(selectionState.start.y, selectionState.current.y);
    const maxX = Math.max(selectionState.start.x, selectionState.current.x);
    const maxY = Math.max(selectionState.start.y, selectionState.current.y);

    const selectedIds = layout.components
      // 그룹 컨테이너는 제외
      .filter((c) => c.type !== "group")
      .filter((c) => {
        const abs = getAbsolutePosition(c);
        const left = abs.x;
        const top = abs.y;
        const right = abs.x + c.size.width;
        const bottom = abs.y + c.size.height;
        // 영역과 교차 여부 판단 (일부라도 겹치면 선택)
        return right >= minX && left <= maxX && bottom >= minY && top <= maxY;
      })
      .map((c) => c.id);

    setGroupState((prev) => ({
      ...prev,
      selectedComponents: Array.from(new Set([...prev.selectedComponents, ...selectedIds])),
    }));
    setSelectionState({ isSelecting: false, start: { x: 0, y: 0 }, current: { x: 0, y: 0 } });
  }, [selectionState, layout.components, getAbsolutePosition]);

  // 선택된 화면의 테이블만 로드 (최적화된 API 사용)
  useEffect(() => {
    const fetchScreenTable = async () => {
      if (!selectedScreen?.tableName) {
        setTables([]);
        return;
      }

      try {
        // console.log(`=== 테이블 정보 조회 시작: ${selectedScreen.tableName} ===`);
        const startTime = performance.now();

        // 최적화된 단일 테이블 조회 API 사용
        const response = await fetch(`http://localhost:8080/api/screen-management/tables/${selectedScreen.tableName}`, {
          headers: {
            Authorization: `Bearer ${localStorage.getItem("authToken")}`,
          },
        });

        const endTime = performance.now();
        // console.log(`테이블 조회 완료: ${(endTime - startTime).toFixed(2)}ms`);

        if (response.ok) {
          const data = await response.json();
          if (data.success && data.data) {
            setTables([data.data]);
            // console.log(`테이블 ${selectedScreen.tableName} 로드 완료, 컬럼 ${data.data.columns.length}개`);
          } else {
            // console.error("테이블 조회 실패:", data.message);
            // 선택된 화면의 테이블에 대한 임시 데이터 생성
            setTables([createMockTableForScreen(selectedScreen.tableName)]);
          }
        } else if (response.status === 404) {
          // console.warn(`테이블 ${selectedScreen.tableName}을 찾을 수 없습니다.`);
          // 테이블이 존재하지 않는 경우 임시 데이터 생성
          setTables([createMockTableForScreen(selectedScreen.tableName)]);
        } else {
          // console.error("테이블 조회 실패:", response.status);
          // 선택된 화면의 테이블에 대한 임시 데이터 생성
          setTables([createMockTableForScreen(selectedScreen.tableName)]);
        }
      } catch (error) {
        // console.error("테이블 조회 중 오류:", error);
        // 선택된 화면의 테이블에 대한 임시 데이터 생성
        setTables([createMockTableForScreen(selectedScreen.tableName)]);
      }
    };

    fetchScreenTable();
  }, [selectedScreen?.tableName]);

  // 검색된 테이블 필터링
  const filteredTables = useMemo(() => {
    if (!searchTerm.trim()) return tables;

    return tables.filter(
      (table) =>
        table.tableName.toLowerCase().includes(searchTerm.toLowerCase()) ||
        table.tableLabel.toLowerCase().includes(searchTerm.toLowerCase()) ||
        table.columns.some(
          (column) =>
            column.columnName.toLowerCase().includes(searchTerm.toLowerCase()) ||
            (column.columnLabel || column.columnName).toLowerCase().includes(searchTerm.toLowerCase()),
        ),
    );
  }, [tables, searchTerm]);

  // 페이징된 테이블
  const paginatedTables = useMemo(() => {
    const startIndex = (currentPage - 1) * itemsPerPage;
    const endIndex = startIndex + itemsPerPage;
    return filteredTables.slice(startIndex, endIndex);
  }, [filteredTables, currentPage, itemsPerPage]);

  // 총 페이지 수 계산
  const totalPages = Math.ceil(filteredTables.length / itemsPerPage);

  // 페이지 변경 핸들러
  const handlePageChange = (page: number) => {
    setCurrentPage(page);
    setExpandedTables(new Set()); // 페이지 변경 시 확장 상태 초기화
  };

  // 검색어 변경 핸들러
  const handleSearchChange = (value: string) => {
    setSearchTerm(value);
    setCurrentPage(1); // 검색 시 첫 페이지로 이동
    setExpandedTables(new Set()); // 검색 시 확장 상태 초기화
  };

  // 임시 테이블 데이터 (API 실패 시 사용)
  // 사용하지 않는 getMockTables 함수 제거됨

  // 특정 테이블에 대한 임시 데이터 생성
  const createMockTableForScreen = (tableName: string): TableInfo => {
    // 기본 컬럼들 생성
    const baseColumns = [
      {
        tableName,
        columnName: "id",
        columnLabel: "ID",
        webType: "number" as WebType,
        dataType: "BIGINT",
        isNullable: "NO",
      },
      {
        tableName,
        columnName: "name",
        columnLabel: "이름",
        webType: "text" as WebType,
        dataType: "VARCHAR",
        isNullable: "NO",
      },
      {
        tableName,
        columnName: "description",
        columnLabel: "설명",
        webType: "textarea" as WebType,
        dataType: "TEXT",
        isNullable: "YES",
      },
      {
        tableName,
        columnName: "created_date",
        columnLabel: "생성일",
        webType: "date" as WebType,
        dataType: "TIMESTAMP",
        isNullable: "NO",
      },
      {
        tableName,
        columnName: "updated_date",
        columnLabel: "수정일",
        webType: "date" as WebType,
        dataType: "TIMESTAMP",
        isNullable: "YES",
      },
    ];

    return {
      tableName,
      tableLabel: `${tableName} (임시)`,
      columns: baseColumns,
    };
  };

  // 테이블 확장/축소 토글
  const toggleTableExpansion = useCallback((tableName: string) => {
    setExpandedTables((prev) => {
      const newSet = new Set(prev);
      if (newSet.has(tableName)) {
        newSet.delete(tableName);
      } else {
        newSet.add(tableName);
      }
      return newSet;
    });
  }, []);

  // 웹타입에 따른 위젯 타입 매핑
  const getWidgetTypeFromWebType = useCallback((webType: string): string => {
    // console.log("getWidgetTypeFromWebType - input webType:", webType);
    switch (webType) {
      case "text":
        return "text";
      case "email":
        return "email";
      case "tel":
        return "tel";
      case "number":
        return "number";
      case "decimal":
        return "decimal";
      case "date":
        return "date";
      case "datetime":
        return "datetime";
      case "select":
        return "select";
      case "dropdown":
        return "dropdown";
      case "textarea":
        return "textarea";
      case "text_area":
        return "text_area";
      case "checkbox":
        return "checkbox";
      case "boolean":
        return "boolean";
      case "radio":
        return "radio";
      case "code":
        return "code";
      case "entity":
        return "entity";
      case "file":
        return "file";
      default:
        // console.log("getWidgetTypeFromWebType - default case, returning text for:", webType);
        return "text";
    }
  }, []);

  // 범용 복사 함수
  const copyComponents = useCallback(() => {
    if (!selectedComponent && groupState.selectedComponents.length === 0) return;

    let componentsToCopy: ComponentData[] = [];
    let copyType: "single" | "multiple" | "group" = "single";

    if (selectedComponent?.type === "group") {
      // 그룹 복사
      const children = getGroupChildren(layout.components, selectedComponent.id);
      componentsToCopy = [selectedComponent, ...children];
      copyType = "group";
    } else if (groupState.selectedComponents.length > 1) {
      // 다중 선택 복사
      componentsToCopy = layout.components.filter((comp) => groupState.selectedComponents.includes(comp.id));
      copyType = "multiple";
    } else if (selectedComponent) {
      // 단일 컴포넌트 복사
      componentsToCopy = [selectedComponent];
      copyType = "single";
    }

    if (componentsToCopy.length === 0) return;

    // 바운딩 박스 계산
    const positions = componentsToCopy.map((comp) => ({
      x: comp.position.x,
      y: comp.position.y,
      width: comp.size.width,
      height: comp.size.height,
    }));

    const minX = Math.min(...positions.map((p) => p.x));
    const minY = Math.min(...positions.map((p) => p.y));
    const maxX = Math.max(...positions.map((p) => p.x + p.width));
    const maxY = Math.max(...positions.map((p) => p.y + p.height));

    setClipboard({
      type: copyType,
      data: componentsToCopy,
      offset: { x: 20, y: 20 },
      boundingBox: { x: minX, y: minY, width: maxX - minX, height: maxY - minY },
    });
  }, [selectedComponent, groupState.selectedComponents, layout.components]);

  // 범용 삭제 함수
  const deleteComponents = useCallback(() => {
    if (!selectedComponent && groupState.selectedComponents.length === 0) return;

    let idsToRemove: string[] = [];

    if (selectedComponent?.type === "group") {
      // 그룹 삭제 (자식 컴포넌트 포함)
      const childrenIds = getGroupChildren(layout.components, selectedComponent.id).map((child) => child.id);
      idsToRemove = [selectedComponent.id, ...childrenIds];
    } else if (groupState.selectedComponents.length > 1) {
      // 다중 선택 삭제
      idsToRemove = [...groupState.selectedComponents];
    } else if (selectedComponent) {
      // 단일 컴포넌트 삭제
      idsToRemove = [selectedComponent.id];
    }

    if (idsToRemove.length === 0) return;

    const newLayout = {
      ...layout,
      components: layout.components.filter((comp) => !idsToRemove.includes(comp.id)),
    };
    setLayout(newLayout);
    saveToHistory(newLayout);

    // 선택 상태 초기화
    setSelectedComponent(null);
    setGroupState((prev) => ({ ...prev, selectedComponents: [] }));
  }, [selectedComponent, groupState.selectedComponents, layout, saveToHistory, setGroupState]);

  // 범용 붙여넣기 함수
  const pasteComponents = useCallback(
    (pastePosition?: { x: number; y: number }) => {
      if (!clipboard || clipboard.data.length === 0) return;

      const idMap = new Map<string, string>();
      const newComponents: ComponentData[] = [];

      // 붙여넣기 위치 결정
      let targetPosition = pastePosition;
      if (!targetPosition && clipboard.boundingBox) {
        targetPosition = {
          x: clipboard.boundingBox.x + clipboard.offset.x,
          y: clipboard.boundingBox.y + clipboard.offset.y,
        };
      }

      const offsetX = targetPosition ? targetPosition.x - (clipboard.boundingBox?.x || 0) : clipboard.offset.x;
      const offsetY = targetPosition ? targetPosition.y - (clipboard.boundingBox?.y || 0) : clipboard.offset.y;

      // 모든 컴포넌트에 대해 새 ID 생성
      clipboard.data.forEach((comp) => {
        const newId = generateComponentId();
        idMap.set(comp.id, newId);
      });

      // 컴포넌트 복사 및 ID/위치 업데이트
      clipboard.data.forEach((comp) => {
        const newComp: ComponentData = {
          ...comp,
          id: idMap.get(comp.id)!,
          position: {
            x: comp.position.x + offsetX,
            y: comp.position.y + offsetY,
          },
          // 부모 ID가 있고 매핑되는 경우 업데이트
          parentId: comp.parentId && idMap.has(comp.parentId) ? idMap.get(comp.parentId)! : undefined,
        };
        newComponents.push(newComp);
      });

      const newLayout = {
        ...layout,
        components: [...layout.components, ...newComponents],
      };
      setLayout(newLayout);
      saveToHistory(newLayout);
    },
    [clipboard, layout, saveToHistory],
  );

  // 캔버스 우클릭 컨텍스트 메뉴
  const handleCanvasContextMenu = useCallback(
    (e: React.MouseEvent) => {
      e.preventDefault();
      // 우클릭 시 붙여넣기 (클립보드에 데이터가 있는 경우)
      if (clipboard && clipboard.data.length > 0) {
        const rect = e.currentTarget.getBoundingClientRect();
        const x = e.clientX - rect.left;
        const y = e.clientY - rect.top;
        pasteComponents({ x, y });
      }
    },
    [clipboard, pasteComponents],
  );

  // 키보드 단축키 지원
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.ctrlKey || e.metaKey) {
        switch (e.key) {
          case "z":
            e.preventDefault();
            if (e.shiftKey) {
              redo(); // Ctrl+Shift+Z 또는 Cmd+Shift+Z
            } else {
              undo(); // Ctrl+Z 또는 Cmd+Z
            }
            break;
          case "y":
            e.preventDefault();
            redo(); // Ctrl+Y 또는 Cmd+Y
            break;
          case "c":
            e.preventDefault();
            // 선택된 컴포넌트(들) 복사
            copyComponents();
            break;
          case "v":
            e.preventDefault();
            // 클립보드 내용 붙여넣기
            if (clipboard && clipboard.data.length > 0) {
              pasteComponents();
            }
            break;
          case "g":
          case "G":
            e.preventDefault();
            if (e.shiftKey) {
              // Ctrl+Shift+G: 그룹 해제
              const selectedComponents = layout.components.filter((comp) =>
                groupState.selectedComponents.includes(comp.id),
              );
              if (selectedComponents.length === 1 && selectedComponents[0].type === "group") {
                // 그룹 해제 로직을 직접 실행
                const group = selectedComponents[0] as any;
                const groupChildren = layout.components.filter((comp) => comp.parentId === group.id);

                // 자식 컴포넌트들의 절대 위치 복원
                const absoluteChildren = groupChildren.map((child) => ({
                  ...child,
                  position: {
                    x: child.position.x + group.position.x,
                    y: child.position.y + group.position.y,
                    z: (child.position as any).z || 1,
                  },
                  parentId: undefined,
                }));

                const newLayout = {
                  ...layout,
                  components: [
                    ...layout.components.filter((comp) => comp.id !== group.id && comp.parentId !== group.id),
                    ...absoluteChildren,
                  ],
                };

                setLayout(newLayout);
                saveToHistory(newLayout);
                setGroupState((prev) => ({
                  ...prev,
                  selectedComponents: [],
                  isGrouping: false,
                }));
              }
            } else {
              // Ctrl+G: 그룹 생성 다이얼로그 열기
              const selectedComponents = layout.components.filter((comp) =>
                groupState.selectedComponents.includes(comp.id),
              );
              if (selectedComponents.length >= 2) {
                setShowGroupCreateDialog(true);
              }
            }
            break;
        }
      } else if (e.key === "Delete") {
        e.preventDefault();
        // 선택된 컴포넌트(들) 삭제
        deleteComponents();
      }
    };

    window.addEventListener("keydown", handleKeyDown);
    return () => window.removeEventListener("keydown", handleKeyDown);
  }, [
    undo,
    redo,
    copyComponents,
    pasteComponents,
    deleteComponents,
    clipboard,
    layout,
    groupState,
    saveToHistory,
    setLayout,
    setGroupState,
    setShowGroupCreateDialog,
  ]);

  // 컴포넌트 속성 업데이트 함수
  const updateComponentProperty = useCallback(
    (componentId: string, propertyPath: string, value: any) => {
      const newLayout = {
        ...layout,
        components: layout.components.map((comp) => {
          if (comp.id === componentId) {
            const newComp = { ...comp };
            const pathParts = propertyPath.split(".");
            let current: any = newComp;

            for (let i = 0; i < pathParts.length - 1; i++) {
              current = current[pathParts[i]];
            }
            current[pathParts[pathParts.length - 1]] = value;

            // 크기 변경 시 격자 스냅 적용
            if (
              (propertyPath === "size.width" || propertyPath === "size.height") &&
              layout.gridSettings?.snapToGrid &&
              gridInfo
            ) {
              const snappedSize = snapSizeToGrid(newComp.size, gridInfo, layout.gridSettings as GridUtilSettings);
              newComp.size = snappedSize;
            }

            return newComp;
          }
          return comp;
        }),
      };
      setLayout(newLayout);
      saveToHistory(newLayout);
      // 선택된 컴포넌트인 경우 즉시 상태도 동기화하여 입력 즉시 반영되도록 처리
      if (selectedComponent && selectedComponent.id === componentId) {
        const updated = newLayout.components.find((c) => c.id === componentId) || null;
        if (updated) setSelectedComponent(updated);
      }
    },
    [layout, saveToHistory, selectedComponent, gridInfo],
  );

  // 그룹 생성 함수
  const handleGroupCreate = useCallback(
    (componentIds: string[], title: string, style?: any) => {
      const selectedComponents = layout.components.filter((comp) => componentIds.includes(comp.id));

      if (selectedComponents.length < 2) {
        return;
      }

      // 경계 박스 계산
      const boundingBox = calculateBoundingBox(selectedComponents);

      // 그룹 컴포넌트 생성 (경계 박스 정보 전달)
      const groupComponent = createGroupComponent(
        componentIds,
        title,
        { x: boundingBox.minX, y: boundingBox.minY },
        { width: boundingBox.width, height: boundingBox.height },
        style,
      );

      // 자식 컴포넌트들의 상대 위치 계산
      const relativeChildren = calculateRelativePositions(
        selectedComponents,
        {
          x: boundingBox.minX,
          y: boundingBox.minY,
        },
        groupComponent.id,
      );

      // 새 레이아웃 생성
      const newLayout = {
        ...layout,
        components: [
          // 그룹에 포함되지 않은 기존 컴포넌트들만 유지
          ...layout.components.filter((comp) => !componentIds.includes(comp.id)),
          // 그룹 컴포넌트 추가
          groupComponent,
          // 자식 컴포넌트들도 유지 (parentId로 그룹과 연결)
          ...relativeChildren,
        ],
      };

      setLayout(newLayout);
      saveToHistory(newLayout);
    },
    [layout, saveToHistory],
  );

  // 그룹 해제 함수
  const handleGroupUngroup = useCallback(
    (groupId: string) => {
      const group = layout.components.find((comp) => comp.id === groupId) as GroupComponent;
      if (!group || group.type !== "group") {
        return;
      }

      const groupChildren = getGroupChildren(layout.components, groupId);

      // 자식 컴포넌트들의 절대 위치 복원
      const absoluteChildren = restoreAbsolutePositions(groupChildren, group.position);

      // 새 레이아웃 생성
      const newLayout = {
        ...layout,
        components: [
          // 그룹과 그룹의 자식 컴포넌트들을 제외한 기존 컴포넌트들
          ...layout.components.filter((comp) => comp.id !== groupId && comp.parentId !== groupId),
          // 절대 위치로 복원된 자식 컴포넌트들
          ...absoluteChildren,
        ],
      };

      setLayout(newLayout);
      saveToHistory(newLayout);
    },
    [layout, saveToHistory],
  );

  // 레이아웃 저장 함수
  const saveLayout = useCallback(async () => {
    if (!selectedScreen) {
      toast.error("저장할 화면이 선택되지 않았습니다.");
      return;
    }

    try {
      setIsSaving(true);
      await screenApi.saveLayout(selectedScreen.screenId, layout);
      setHasUnsavedChanges(false); // 저장 완료 시 변경사항 플래그 해제
      toast.success("레이아웃이 성공적으로 저장되었습니다.");
    } catch (error) {
      // console.error("레이아웃 저장 실패:", error);
      toast.error("레이아웃 저장에 실패했습니다.");
    } finally {
      setIsSaving(false);
    }
  }, [layout, selectedScreen]);

  // 레이아웃 로드 함수
  const loadLayout = useCallback(async () => {
    if (!selectedScreen) return;

    try {
      setIsLoading(true);
      const savedLayout = await screenApi.getLayout(selectedScreen.screenId);

      if (savedLayout && savedLayout.components) {
        // 격자 설정이 없는 경우 기본값 추가
        if (!savedLayout.gridSettings) {
          savedLayout.gridSettings = { columns: 12, gap: 16, padding: 16, snapToGrid: true };
        } else if (savedLayout.gridSettings.snapToGrid === undefined) {
          savedLayout.gridSettings.snapToGrid = true;
        }

        setLayout(savedLayout);
        // 히스토리 초기화
        setHistory([savedLayout]);
        setHistoryIndex(0);
        setHasUnsavedChanges(false); // 로드 완료 시 변경사항 플래그 해제
        toast.success("레이아웃을 불러왔습니다.");
      } else {
        // 저장된 레이아웃이 없는 경우 기본 레이아웃 유지
        const defaultLayout = {
          components: [],
          gridSettings: { columns: 12, gap: 16, padding: 16, snapToGrid: true },
        };
        setLayout(defaultLayout);
        setHistory([defaultLayout]);
        setHistoryIndex(0);
        setHasUnsavedChanges(false);
      }
    } catch (error) {
      // console.error("레이아웃 로드 실패:", error);
      // 에러 시에도 기본 레이아웃으로 초기화
      const defaultLayout = {
        components: [],
        gridSettings: { columns: 12, gap: 16, padding: 16, snapToGrid: true },
      };
      setLayout(defaultLayout);
      setHistory([defaultLayout]);
      setHistoryIndex(0);
      setHasUnsavedChanges(false);
      toast.error("레이아웃 로드에 실패했습니다. 새 레이아웃으로 시작합니다.");
    } finally {
      setIsLoading(false);
    }
  }, [selectedScreen]);

  // 화면 선택 시 레이아웃 로드
  useEffect(() => {
    if (selectedScreen) {
      loadLayout();
    }
  }, [selectedScreen, loadLayout]);

  // 스크롤 컨테이너 참조 (좌표 계산 정확도 향상)
  const scrollContainerRef = useRef<HTMLDivElement | null>(null);

  // 드래그 시작 (새 컴포넌트 추가)
  const startDrag = useCallback((component: Partial<ComponentData>, e: React.DragEvent) => {
    const canvasRect = canvasRef.current?.getBoundingClientRect();
    const scrollLeft = scrollContainerRef.current?.scrollLeft || 0;
    const scrollTop = scrollContainerRef.current?.scrollTop || 0;
    const relMouseX = (canvasRect ? e.clientX - canvasRect.left : 0) + scrollLeft;
    const relMouseY = (canvasRect ? e.clientY - canvasRect.top : 0) + scrollTop;

    setDragState({
      isDragging: true,
      draggedComponent: component as ComponentData,
      draggedComponents: [component as ComponentData],
      originalPosition: { x: 0, y: 0 },
      currentPosition: { x: relMouseX, y: relMouseY },
      isMultiDrag: false,
      initialMouse: { x: relMouseX, y: relMouseY },
      grabOffset: { x: 0, y: 0 },
    });
    e.dataTransfer.setData("application/json", JSON.stringify(component));
  }, []);

  // 기존 컴포넌트 드래그 시작 (재배치)
  const startComponentDrag = useCallback(
    (component: ComponentData, e: React.DragEvent) => {
      e.stopPropagation();

      // 다중선택된 컴포넌트들이 있는지 확인
      const selectedComponents = layout.components.filter((comp) => groupState.selectedComponents.includes(comp.id));

      const isMultiDrag = selectedComponents.length > 1 && groupState.selectedComponents.includes(component.id);

      // 마우스-컴포넌트 그랩 오프셋 계산 (커서와 컴포넌트 좌측상단의 거리)
      const canvasRect = canvasRef.current?.getBoundingClientRect();
      const scrollLeft = scrollContainerRef.current?.scrollLeft || 0;
      const scrollTop = scrollContainerRef.current?.scrollTop || 0;
      const relMouseX = (canvasRect ? e.clientX - canvasRect.left : 0) + scrollLeft;
      const relMouseY = (canvasRect ? e.clientY - canvasRect.top : 0) + scrollTop;
      const grabOffsetX = relMouseX - component.position.x;
      const grabOffsetY = relMouseY - component.position.y;

      if (isMultiDrag) {
        // 다중 드래그
        setDragState({
          isDragging: true,
          draggedComponent: component,
          draggedComponents: selectedComponents,
          originalPosition: component.position,
          currentPosition: { x: relMouseX, y: relMouseY },
          isMultiDrag: true,
          initialMouse: { x: relMouseX, y: relMouseY },
          grabOffset: { x: grabOffsetX, y: grabOffsetY },
        });
        e.dataTransfer.setData(
          "application/json",
          JSON.stringify({
            ...component,
            isMoving: true,
            isMultiDrag: true,
            selectedComponentIds: groupState.selectedComponents,
          }),
        );
      } else {
        // 단일 드래그
        setDragState({
          isDragging: true,
          draggedComponent: component,
          draggedComponents: [component],
          originalPosition: component.position,
          currentPosition: { x: relMouseX, y: relMouseY },
          isMultiDrag: false,
          initialMouse: { x: relMouseX, y: relMouseY },
          grabOffset: { x: grabOffsetX, y: grabOffsetY },
        });
        e.dataTransfer.setData("application/json", JSON.stringify({ ...component, isMoving: true }));
      }
    },
    [layout.components, groupState.selectedComponents],
  );

  // 드래그 중
  const onDragOver = useCallback(
    (e: React.DragEvent) => {
      e.preventDefault();
      if (dragState.isDragging) {
        const rect = canvasRef.current?.getBoundingClientRect();
        // 스크롤 오프셋 추가하여 컨텐츠 좌표로 변환 (상위 스크롤 컨테이너 기준)
        const scrollLeft = scrollContainerRef.current?.scrollLeft || 0;
        const scrollTop = scrollContainerRef.current?.scrollTop || 0;
        const x = rect ? e.clientX - rect.left + scrollLeft : 0;
        const y = rect ? e.clientY - rect.top + scrollTop : 0;

        setDragState((prev) => ({
          ...prev,
          currentPosition: { x, y },
        }));
      }
    },
    [dragState.isDragging],
  );

  // 드롭 처리
  const onDrop = useCallback(
    (e: React.DragEvent) => {
      e.preventDefault();

      try {
        const data = JSON.parse(e.dataTransfer.getData("application/json"));

        if (data.isMoving) {
          // 기존 컴포넌트 재배치
          const rect = canvasRef.current?.getBoundingClientRect();
          // 스크롤 오프셋 추가하여 컨텐츠 좌표로 변환 (상위 스크롤 컨테이너 기준)
          const scrollLeft = scrollContainerRef.current?.scrollLeft || 0;
          const scrollTop = scrollContainerRef.current?.scrollTop || 0;
          const mouseX = rect ? e.clientX - rect.left + scrollLeft : 0;
          const mouseY = rect ? e.clientY - rect.top + scrollTop : 0;

          if (data.isMultiDrag && data.selectedComponentIds) {
            // 다중 드래그 처리
            // 그랩한 컴포넌트의 시작 위치 기준 델타 계산 (그랩 오프셋 반영)
            const dropX = mouseX - dragState.grabOffset.x;
            const dropY = mouseY - dragState.grabOffset.y;
            const deltaX = dropX - dragState.originalPosition.x;
            const deltaY = dropY - dragState.originalPosition.y;

            const newLayout = {
              ...layout,
              components: layout.components.map((comp) => {
                if (data.selectedComponentIds.includes(comp.id)) {
                  let newX = comp.position.x + deltaX;
                  let newY = comp.position.y + deltaY;

                  // 격자 스냅 적용
                  if (layout.gridSettings?.snapToGrid && gridInfo) {
                    const snappedPosition = snapToGrid(
                      { x: newX, y: newY, z: comp.position.z || 1 } as Required<Position>,
                      gridInfo,
                      layout.gridSettings as GridUtilSettings,
                    );
                    newX = snappedPosition.x;
                    newY = snappedPosition.y;
                  }

                  return {
                    ...comp,
                    position: {
                      x: newX,
                      y: newY,
                      z: comp.position.z || 1,
                    },
                  };
                }
                return comp;
              }),
            };
            setLayout(newLayout);
            saveToHistory(newLayout);
          } else {
            // 단일 드래그 처리
            let x = mouseX - dragState.grabOffset.x;
            let y = mouseY - dragState.grabOffset.y;

            // 격자 스냅 적용
            if (layout.gridSettings?.snapToGrid && gridInfo) {
              const snappedPosition = snapToGrid(
                { x, y, z: 1 } as Required<Position>,
                gridInfo,
                layout.gridSettings as GridUtilSettings,
              );
              x = snappedPosition.x;
              y = snappedPosition.y;
            }

            const newLayout = {
              ...layout,
              components: layout.components.map((comp) =>
                comp.id === data.id ? { ...comp, position: { x, y, z: comp.position.z || 1 } } : comp,
              ),
            };
            setLayout(newLayout);
            saveToHistory(newLayout);
          }
        } else {
          // 새 컴포넌트 추가
          const rect = canvasRef.current?.getBoundingClientRect();
          // 스크롤 오프셋 추가하여 컨텐츠 좌표로 변환 (상위 스크롤 컨테이너 기준)
          const scrollLeft = scrollContainerRef.current?.scrollLeft || 0;
          const scrollTop = scrollContainerRef.current?.scrollTop || 0;
          let x = rect ? e.clientX - rect.left + scrollLeft : 0;
          let y = rect ? e.clientY - rect.top + scrollTop : 0;

          // 격자 스냅 적용
          if (layout.gridSettings?.snapToGrid && gridInfo) {
            const snappedPosition = snapToGrid(
              { x, y, z: 1 } as Required<Position>,
              gridInfo,
              layout.gridSettings as GridUtilSettings,
            );
            x = snappedPosition.x;
            y = snappedPosition.y;
          }

          // 기본 크기를 격자에 맞춰 설정
          let defaultWidth = data.size?.width || 200;
          const defaultHeight = data.size?.height || 100;

          if (layout.gridSettings?.snapToGrid && gridInfo) {
            const { columnWidth } = gridInfo;
            const { gap } = layout.gridSettings;
            // 기본적으로 1컬럼 너비로 설정
            const gridColumns = 1;
            defaultWidth = gridColumns * columnWidth + (gridColumns - 1) * gap;
          }

          const newComponent: ComponentData = {
            ...data,
            id: generateComponentId(),
            position: { x, y, z: 1 },
            size: { width: defaultWidth, height: defaultHeight },
          } as ComponentData;

          const newLayout = {
            ...layout,
            components: [...layout.components, newComponent],
          };
          setLayout(newLayout);
          saveToHistory(newLayout);
        }
      } catch (error) {
        // console.error("드롭 처리 중 오류:", error);
      }

      setDragState({
        isDragging: false,
        draggedComponent: null,
        draggedComponents: [],
        originalPosition: { x: 0, y: 0 },
        currentPosition: { x: 0, y: 0 },
        isMultiDrag: false,
        initialMouse: { x: 0, y: 0 },
        grabOffset: { x: 0, y: 0 },
      });
    },
    [
      layout,
      saveToHistory,
      dragState.initialMouse.x,
      dragState.initialMouse.y,
      dragState.grabOffset.x,
      dragState.grabOffset.y,
      gridInfo,
    ],
  );

  // 드래그 종료
  const endDrag = useCallback(() => {
    // 격자 스냅 적용
    if (dragState.isDragging && dragState.draggedComponent && gridInfo && layout.gridSettings?.snapToGrid) {
      const component = dragState.draggedComponent;
      const snappedPosition = snapToGrid(dragState.currentPosition, gridInfo, layout.gridSettings as GridUtilSettings);

      // 스냅된 위치로 컴포넌트 업데이트
      if (snappedPosition.x !== dragState.currentPosition.x || snappedPosition.y !== dragState.currentPosition.y) {
        const updatedComponents = layout.components.map((comp) =>
          comp.id === component.id ? { ...comp, position: snappedPosition } : comp,
        );

        const newLayout = { ...layout, components: updatedComponents };
        setLayout(newLayout);
        saveToHistory(newLayout);
      }
    }

    setDragState({
      isDragging: false,
      draggedComponent: null,
      draggedComponents: [],
      originalPosition: { x: 0, y: 0 },
      currentPosition: { x: 0, y: 0 },
      isMultiDrag: false,
      initialMouse: { x: 0, y: 0 },
      grabOffset: { x: 0, y: 0 },
    });
  }, [dragState, gridInfo, layout, saveToHistory]);

  // 컴포넌트 클릭 (선택)
  const handleComponentClick = useCallback(
    (component: ComponentData, event?: React.MouseEvent) => {
      const isShiftPressed = event?.shiftKey || false;
      const isGroupContainer = component.type === "group";

      if (groupState.isGrouping || isShiftPressed) {
        // 그룹화 모드이거나 시프트 키를 누른 경우 다중 선택
        if (isGroupContainer) {
          // 그룹 컨테이너는 다중선택에서 제외하고 단일 선택으로 처리
          setSelectedComponent(component);
          setGroupState((prev) => ({
            ...prev,
            selectedComponents: [component.id],
            isGrouping: false, // 그룹 선택 시 그룹화 모드 해제
          }));
          return;
        }
        const isSelected = groupState.selectedComponents.includes(component.id);
        setGroupState((prev) => ({
          ...prev,
          selectedComponents: isSelected
            ? prev.selectedComponents.filter((id) => id !== component.id)
            : [...prev.selectedComponents, component.id],
        }));

        // 시프트 키로 선택한 경우 마지막 선택된 컴포넌트를 selectedComponent로 설정
        if (isShiftPressed) {
          setSelectedComponent(component);
        }
      } else {
        // 일반 모드에서는 단일 선택
        setSelectedComponent(component);
        setGroupState((prev) => ({
          ...prev,
          selectedComponents: [component.id], // 그룹도 선택 가능하도록 수정
        }));
      }
    },
    [groupState.isGrouping, groupState.selectedComponents],
  );

  // 화면이 선택되지 않았을 때 처리
  if (!selectedScreen) {
    return (
      <div className="flex h-full items-center justify-center">
        <div className="text-center text-gray-500">
          <Palette className="mx-auto mb-4 h-16 w-16 text-gray-300" />
          <p className="mb-4 text-lg">설계할 화면을 선택해주세요</p>
          <p className="mb-6 text-sm">화면 목록에서 화면을 선택한 후 설계기를 사용하세요</p>
          <Button onClick={onBackToList} variant="outline">
            화면 목록으로 돌아가기
          </Button>
        </div>
      </div>
    );
  }

  return (
    <div className="flex h-screen w-full flex-col bg-gray-100">
      {/* 상단 툴바 */}
      <DesignerToolbar
        screenName={selectedScreen?.screenName}
        tableName={selectedScreen?.tableName}
        onBack={onBackToList}
        onSave={handleSave}
        onUndo={undo}
        onRedo={redo}
        onPreview={() => {
          // TODO: 미리보기 기능 구현
          toast.info("미리보기 기능은 준비 중입니다.");
        }}
        onTogglePanel={togglePanel}
        panelStates={panelStates}
        canUndo={historyIndex > 0}
        canRedo={historyIndex < history.length - 1}
        isSaving={isSaving}
      />

      {/* 메인 캔버스 영역 (전체 화면) */}
      <div 
        className="flex-1 relative overflow-hidden bg-white" 
        onClick={(e) => {
          if (e.target === e.currentTarget) {
            closeAllPanels();
            setSelectedComponent(null);
            setGroupState(prev => ({ ...prev, selectedComponents: [] }));
          }
        }}
        onDrop={handleDrop}
        onDragOver={handleDragOver}
          <Badge variant="outline" className="font-mono">
            {selectedScreen.tableName}
          </Badge>
          {clipboard && clipboard.data.length > 0 && (
            <Badge variant="secondary" className="text-xs">
              <Clipboard className="mr-1 h-3 w-3" />
              {clipboard.type === "group"
                ? "그룹 복사됨"
                : clipboard.type === "multiple"
                  ? `${clipboard.data.length}개 복사됨`
                  : "컴포넌트 복사됨"}
            </Badge>
          )}
        </div>
        <div className="flex items-center space-x-2">
          <Button
            variant={groupState.isGrouping ? "default" : "outline"}
            size="sm"
            onClick={() => setGroupState((prev) => ({ ...prev, isGrouping: !prev.isGrouping }))}
            title="그룹화 모드 토글 (일반 모드에서도 Shift+클릭으로 다중선택 가능)"
          >
            <Group className="mr-2 h-4 w-4" />
            {groupState.isGrouping ? "그룹화 모드" : "일반 모드"}
          </Button>

          {/* 복사/붙여넣기/삭제 버튼들 */}
          {(selectedComponent || groupState.selectedComponents.length > 0) && (
            <>
              <Button variant="outline" size="sm" onClick={copyComponents} title="복사 (Ctrl+C)">
                <Copy className="mr-2 h-4 w-4" />
                복사
              </Button>
              <Button variant="destructive" size="sm" onClick={deleteComponents} title="삭제 (Delete 키)">
                <Trash2 className="mr-2 h-4 w-4" />
                삭제
              </Button>
            </>
          )}

          {/* 붙여넣기 버튼 */}
          {clipboard && clipboard.data.length > 0 && (
            <Button variant="outline" size="sm" onClick={() => pasteComponents()} title="붙여넣기 (Ctrl+V)">
              <Clipboard className="mr-2 h-4 w-4" />
              붙여넣기
            </Button>
          )}

          <Button variant="outline" size="sm" onClick={undo} disabled={historyIndex <= 0} title="실행 취소 (Ctrl+Z)">
            <Undo className="mr-2 h-4 w-4" />
            실행 취소
          </Button>
          <Button
            variant="outline"
            size="sm"
            onClick={redo}
            disabled={historyIndex >= history.length - 1}
            title="다시 실행 (Ctrl+Y)"
          >
            <Redo className="mr-2 h-4 w-4" />
            다시 실행
          </Button>
          <Button
            onClick={saveLayout}
            disabled={isSaving || !selectedScreen}
            className={`${hasUnsavedChanges ? "bg-orange-600 hover:bg-orange-700" : "bg-blue-600 hover:bg-blue-700"}`}
          >
            <Save className="mr-2 h-4 w-4" />
            {isSaving ? "저장 중..." : hasUnsavedChanges ? "저장 *" : "저장"}
          </Button>
        </div>
      </div>

      {/* 그룹화 툴바 */}
      <GroupingToolbar
        groupState={groupState}
        onGroupStateChange={setGroupState}
        onGroupCreate={handleGroupCreate}
        onGroupUngroup={handleGroupUngroup}
        selectedComponents={layout.components.filter((comp) => groupState.selectedComponents.includes(comp.id))}
        allComponents={layout.components}
        onGroupAlign={(mode) => {
          const selected = layout.components.filter((c) => groupState.selectedComponents.includes(c.id));
          if (selected.length < 2) return;

          let newComponents = [...layout.components];
          const minX = Math.min(...selected.map((c) => c.position.x));
          const maxX = Math.max(...selected.map((c) => c.position.x + c.size.width));
          const minY = Math.min(...selected.map((c) => c.position.y));
          const maxY = Math.max(...selected.map((c) => c.position.y + c.size.height));
          const centerX = (minX + maxX) / 2;
          const centerY = (minY + maxY) / 2;

          newComponents = newComponents.map((c) => {
            if (!groupState.selectedComponents.includes(c.id)) return c;
            if (mode === "left") return { ...c, position: { x: minX, y: c.position.y } };
            if (mode === "right") return { ...c, position: { x: maxX - c.size.width, y: c.position.y } };
            if (mode === "centerX")
              return { ...c, position: { x: Math.round(centerX - c.size.width / 2), y: c.position.y } };
            if (mode === "top") return { ...c, position: { x: c.position.x, y: minY } };
            if (mode === "bottom") return { ...c, position: { x: c.position.x, y: maxY - c.size.height } };
            if (mode === "centerY")
              return { ...c, position: { x: c.position.x, y: Math.round(centerY - c.size.height / 2) } };
            return c;
          });

          const newLayout = { ...layout, components: newComponents };
          setLayout(newLayout);
          saveToHistory(newLayout);
        }}
        onGroupDistribute={(orientation) => {
          const selected = layout.components.filter((c) => groupState.selectedComponents.includes(c.id));
          if (selected.length < 3) return; // 균등 분배는 3개 이상 권장

          const sorted = [...selected].sort((a, b) =>
            orientation === "horizontal" ? a.position.x - b.position.x : a.position.y - b.position.y,
          );

          if (orientation === "horizontal") {
            const left = sorted[0].position.x;
            const right = Math.max(...sorted.map((c) => c.position.x + c.size.width));
            const totalWidth = right - left;
            const gaps = sorted.length - 1;
            const usedWidth = sorted.reduce((sum, c) => sum + c.size.width, 0);
            const gapSize = gaps > 0 ? Math.max(0, Math.round((totalWidth - usedWidth) / gaps)) : 0;

            let cursor = left;
            sorted.forEach((c, idx) => {
              c.position.x = cursor;
              cursor += c.size.width + gapSize;
            });
          } else {
            const top = sorted[0].position.y;
            const bottom = Math.max(...sorted.map((c) => c.position.y + c.size.height));
            const totalHeight = bottom - top;
            const gaps = sorted.length - 1;
            const usedHeight = sorted.reduce((sum, c) => sum + c.size.height, 0);
            const gapSize = gaps > 0 ? Math.max(0, Math.round((totalHeight - usedHeight) / gaps)) : 0;

            let cursor = top;
            sorted.forEach((c, idx) => {
              c.position.y = cursor;
              cursor += c.size.height + gapSize;
            });
          }

          const newLayout = { ...layout, components: [...layout.components] };
          setLayout(newLayout);
          saveToHistory(newLayout);
        }}
        showCreateDialog={showGroupCreateDialog}
        onShowCreateDialogChange={setShowGroupCreateDialog}
      />

      {/* 메인 컨텐츠 영역 */}
      <div className="flex flex-1 overflow-hidden">
        {/* 좌측 사이드바 - 테이블 타입 */}
        <div className="flex w-80 flex-col border-r bg-muted">
          <div className="border-b bg-white p-4">
            <div className="mb-4">
              <h3 className="text-lg font-medium">테이블 타입</h3>
              {selectedScreen && (
                <div className="mt-2 rounded-md bg-accent p-3">
                  <div className="text-sm font-medium text-blue-900">선택된 화면</div>
                  <div className="text-xs text-blue-700">{selectedScreen.screenName}</div>
                  <div className="mt-1 flex items-center space-x-2">
                    <Database className="h-3 w-3 text-primary" />
                    <span className="font-mono text-xs text-blue-800">{selectedScreen.tableName}</span>
                  </div>
                </div>
              )}
            </div>

            {/* 검색 입력창 */}
            <div className="mb-4">
              <input
                type="text"
                placeholder="테이블명, 컬럼명으로 검색..."
                value={searchTerm}
                onChange={(e) => handleSearchChange(e.target.value)}
                className="w-full rounded-md border border-gray-300 px-3 py-2 focus:border-transparent focus:ring-2 focus:ring-blue-500 focus:outline-none"
              />
            </div>

            {/* 검색 결과 정보 */}
            <div className="mb-2 text-sm text-muted-foreground">
              총 {filteredTables.length}개 테이블 중 {(currentPage - 1) * itemsPerPage + 1}-
              {Math.min(currentPage * itemsPerPage, filteredTables.length)}번째
            </div>

            <p className="mb-4 text-sm text-muted-foreground">테이블과 컬럼을 드래그하여 캔버스에 배치하세요.</p>
          </div>

          {/* 테이블 목록 */}
          <div className="flex-1 overflow-y-auto">
            {paginatedTables.length === 0 ? (
              <div className="flex h-full items-center justify-center p-8">
                <div className="text-center">
                  <Database className="mx-auto mb-4 h-12 w-12 text-gray-300" />
                  <h3 className="mb-2 text-sm font-medium text-gray-900">
                    {selectedScreen ? "테이블 정보를 불러오는 중..." : "화면을 선택해주세요"}
                  </h3>
                  <p className="text-xs text-gray-500">
                    {selectedScreen
                      ? `${selectedScreen.tableName} 테이블의 컬럼 정보를 조회하고 있습니다.`
                      : "화면을 선택하면 해당 테이블의 컬럼 정보가 표시됩니다."}
                  </p>
                </div>
              </div>
            ) : (
              paginatedTables.map((table) => (
                <div key={table.tableName} className="border-b bg-white">
                  {/* 테이블 헤더 */}
                  <div
                    className="flex cursor-pointer items-center justify-between p-3 hover:bg-gray-100"
                    draggable
                    onDragStart={(e) =>
                      startDrag(
                        {
                          type: "container",
                          tableName: table.tableName,
                          label: table.tableLabel,
                          size: { width: 200, height: 80 }, // 픽셀 단위로 변경
                        },
                        e,
                      )
                    }
                  >
                    <div className="flex items-center space-x-2">
                      <Database className="h-4 w-4 text-primary" />
                      <div>
                        <div className="text-sm font-medium">{table.tableLabel}</div>
                        <div className="text-xs text-gray-500">{table.tableName}</div>
                      </div>
                    </div>
                    <Button
                      variant="ghost"
                      size="sm"
                      onClick={() => toggleTableExpansion(table.tableName)}
                      className="h-6 w-6 p-0"
                    >
                      {expandedTables.has(table.tableName) ? (
                        <ChevronDown className="h-4 w-4" />
                      ) : (
                        <ChevronRight className="h-4 w-4" />
                      )}
                    </Button>
                  </div>

                  {/* 컬럼 목록 */}
                  {expandedTables.has(table.tableName) && (
                    <div className="bg-gray-25 border-t">
                      {table.columns.map((column) => (
                        <div
                          key={column.columnName}
                          className="flex cursor-pointer items-center space-x-2 p-2 pl-6 hover:bg-gray-100"
                          draggable
                          onDragStart={(e) => {
                            // console.log("Drag start - column:", column.columnName, "webType:", column.webType);
                            const widgetType = getWidgetTypeFromWebType(column.webType || "text");
                            // console.log("Drag start - widgetType:", widgetType);
                            startDrag(
                              {
                                type: "widget",
                                tableName: table.tableName,
                                columnName: column.columnName,
                                widgetType: widgetType as WebType,
                                label: column.columnLabel || column.columnName,
                                size: { width: 150, height: 40 }, // 픽셀 단위로 변경
                              },
                              e,
                            );
                          }}
                        >
                          <div className="flex-shrink-0">
                            {column.webType === "text" && <Type className="h-3 w-3 text-primary" />}
                            {column.webType === "email" && <Type className="h-3 w-3 text-primary" />}
                            {column.webType === "tel" && <Type className="h-3 w-3 text-primary" />}
                            {column.webType === "number" && <Hash className="h-3 w-3 text-green-600" />}
                            {column.webType === "decimal" && <Hash className="h-3 w-3 text-green-600" />}
                            {column.webType === "date" && <Calendar className="h-3 w-3 text-purple-600" />}
                            {column.webType === "datetime" && <Calendar className="h-3 w-3 text-purple-600" />}
                            {column.webType === "select" && <List className="h-3 w-3 text-orange-600" />}
                            {column.webType === "dropdown" && <List className="h-3 w-3 text-orange-600" />}
                            {column.webType === "textarea" && <AlignLeft className="h-3 w-3 text-indigo-600" />}
                            {column.webType === "text_area" && <AlignLeft className="h-3 w-3 text-indigo-600" />}
                            {column.webType === "checkbox" && <CheckSquare className="h-3 w-3 text-primary" />}
                            {column.webType === "boolean" && <CheckSquare className="h-3 w-3 text-primary" />}
                            {column.webType === "radio" && <Radio className="h-3 w-3 text-primary" />}
                            {column.webType === "code" && <Code className="h-3 w-3 text-muted-foreground" />}
                            {column.webType === "entity" && <Building className="h-3 w-3 text-cyan-600" />}
                            {column.webType === "file" && <File className="h-3 w-3 text-yellow-600" />}
                          </div>
                          <div className="flex-1">
                            <div className="text-sm font-medium">{column.columnLabel || column.columnName}</div>
                            <div className="text-xs text-gray-500">{column.columnName}</div>
                          </div>
                        </div>
                      ))}
                    </div>
                  )}
                </div>
              ))
            )}
          </div>

          {/* 페이징 컨트롤 */}
          {totalPages > 1 && (
            <div className="border-t bg-white p-4">
              <div className="flex items-center justify-between">
                <Button
                  variant="outline"
                  size="sm"
                  onClick={() => handlePageChange(currentPage - 1)}
                  disabled={currentPage === 1}
                >
                  이전
                </Button>

                <div className="text-sm text-muted-foreground">
                  {currentPage} / {totalPages}
                </div>

                <Button
                  variant="outline"
                  size="sm"
                  onClick={() => handlePageChange(currentPage + 1)}
                  disabled={currentPage === totalPages}
                >
                  다음
                </Button>
              </div>
            </div>
          )}
        </div>

        {/* 중앙: 캔버스 영역 */}
        <div className="flex-1 bg-white" ref={scrollContainerRef}>
          <div className="h-full w-full overflow-auto p-6">
            <div
              className="min-h-full rounded-lg border-2 border-dashed border-gray-300 bg-muted p-4"
              onDrop={onDrop}
              onDragOver={onDragOver}
              ref={canvasRef}
              onMouseDown={handleMarqueeStart}
              onMouseMove={handleMarqueeMove}
              onMouseUp={handleMarqueeEnd}
              onContextMenu={handleCanvasContextMenu}
            >
              {/* 항상 격자와 캔버스 표시 */}
              <div className="relative min-h-[600px]" ref={canvasRef}>
                {/* 동적 그리드 가이드 */}
                <div className="pointer-events-none absolute inset-0">
                  <div
                    className="grid h-full gap-1"
                    style={{
                      gridTemplateColumns: `repeat(${layout.gridSettings?.columns || 12}, 1fr)`,
                      gap: `${layout.gridSettings?.gap || 16}px`,
                      padding: `${layout.gridSettings?.padding || 16}px`,
                    }}
                  >
                    {Array.from({ length: layout.gridSettings?.columns || 12 }).map((_, i) => (
                      <div key={i} className="border-r border-gray-200 opacity-30 last:border-r-0" />
                    ))}
                  </div>

                  {/* 격자 스냅이 활성화된 경우 추가 가이드라인 */}
                  {layout.gridSettings?.snapToGrid && gridInfo && (
                    <div className="absolute inset-0">
                      {generateGridLines(
                        canvasRef.current?.clientWidth || 800,
                        canvasRef.current?.clientHeight || 600,
                        layout.gridSettings as GridUtilSettings,
                      ).verticalLines.map((x, i) => (
                        <div
                          key={`v-${i}`}
                          className="absolute top-0 bottom-0 w-px bg-blue-200 opacity-50"
                          style={{ left: `${x}px` }}
                        />
                      ))}
                      {generateGridLines(
                        canvasRef.current?.clientWidth || 800,
                        canvasRef.current?.clientHeight || 600,
                        layout.gridSettings as GridUtilSettings,
                      ).horizontalLines.map((y, i) => (
                        <div
                          key={`h-${i}`}
                          className="absolute right-0 left-0 h-px bg-blue-200 opacity-50"
                          style={{ top: `${y}px` }}
                        />
                      ))}
                    </div>
                  )}
                </div>

                {/* 마키 선택 사각형 */}
                {selectionState.isSelecting && (
                  <div
                    className="pointer-events-none absolute z-50 border border-blue-400 bg-blue-200/20"
                    style={{
                      left: `${Math.min(selectionState.start.x, selectionState.current.x)}px`,
                      top: `${Math.min(selectionState.start.y, selectionState.current.y)}px`,
                      width: `${Math.abs(selectionState.current.x - selectionState.start.x)}px`,
                      height: `${Math.abs(selectionState.current.y - selectionState.start.y)}px`,
                    }}
                  />
                )}

                {/* 컴포넌트들 - 실시간 미리보기 */}
                {layout.components
                  .filter((component) => !component.parentId) // 최상위 컴포넌트만 렌더링
                  .map((component) => {
                    // 그룹 컴포넌트인 경우 자식 컴포넌트들 가져오기
                    const children =
                      component.type === "group"
                        ? layout.components.filter((child) => child.parentId === component.id)
                        : [];

                    return (
                      <RealtimePreview
                        key={component.id}
                        component={component}
                        isSelected={
                          selectedComponent?.id === component.id || groupState.selectedComponents.includes(component.id)
                        }
                        onClick={(e) => handleComponentClick(component, e)}
                        onDragStart={(e) => startComponentDrag(component, e)}
                        onDragEnd={endDrag}
                        onGroupToggle={(groupId) => {
                          // 그룹 접기/펼치기 토글
                          const groupComp = component as GroupComponent;
                          updateComponentProperty(groupId, "collapsed", !groupComp.collapsed);
                        }}
                      >
                        {children.map((child) => (
                          <RealtimePreview
                            key={child.id}
                            component={child}
                            isSelected={groupState.selectedComponents.includes(child.id)}
                            onClick={(e) => handleComponentClick(child, e)}
                            onDragStart={(e) => startComponentDrag(child, e)}
                            onDragEnd={endDrag}
                          />
                        ))}
                      </RealtimePreview>
                    );
                  })}
              </div>
            </div>
          </div>
        </div>

        {/* 우측: 컴포넌트 스타일 편집 */}
        <div className="w-80 border-l bg-muted">
          <div className="h-full space-y-4 overflow-y-auto p-4">
            {/* 격자 설정 */}
            <GridControls
              gridSettings={layout.gridSettings as GridUtilSettings}
              onGridSettingsChange={handleGridSettingsChange}
            />

            <h3 className="text-lg font-medium">컴포넌트 속성</h3>

            {selectedComponent ? (
              <div className="space-y-4">
                <Card>
                  <CardHeader className="pb-3">
                    <CardTitle className="text-sm font-medium">
                      {selectedComponent.type === "container" && "테이블 속성"}
                      {selectedComponent.type === "widget" && "위젯 속성"}
                    </CardTitle>
                  </CardHeader>
                  <CardContent className="space-y-4">
                    {/* 위치 속성 */}
                    <div className="grid grid-cols-2 gap-4">
                      <div className="space-y-2">
                        <Label htmlFor="positionX">X 위치</Label>
                        <Input
                          id="positionX"
                          type="number"
                          min="0"
                          value={liveSelectedPosition.x}
                          onChange={(e) => {
                            const val = (e.target as HTMLInputElement).valueAsNumber;
                            if (Number.isFinite(val)) {
                              let newX = Math.round(val);

                              // 격자 스냅이 활성화된 경우 격자에 맞춤
                              if (layout.gridSettings?.snapToGrid && gridInfo) {
                                const snappedPos = snapToGrid(
                                  {
                                    x: newX,
                                    y: selectedComponent.position.y,
                                    z: selectedComponent.position.z || 1,
                                  } as Required<Position>,
                                  gridInfo,
                                  layout.gridSettings as GridUtilSettings,
                                );
                                newX = snappedPos.x;
                              }

                              updateComponentProperty(selectedComponent.id, "position.x", newX);
                            }
                          }}
                        />
                      </div>
                      <div className="space-y-2">
                        <Label htmlFor="positionY">Y 위치</Label>
                        <Input
                          id="positionY"
                          type="number"
                          min="0"
                          value={liveSelectedPosition.y}
                          onChange={(e) => {
                            const val = (e.target as HTMLInputElement).valueAsNumber;
                            if (Number.isFinite(val)) {
                              let newY = Math.round(val);

                              // 격자 스냅이 활성화된 경우 격자에 맞춤
                              if (layout.gridSettings?.snapToGrid && gridInfo) {
                                const snappedPos = snapToGrid(
                                  {
                                    x: selectedComponent.position.x,
                                    y: newY,
                                    z: selectedComponent.position.z || 1,
                                  } as Required<Position>,
                                  gridInfo,
                                  layout.gridSettings as GridUtilSettings,
                                );
                                newY = snappedPos.y;
                              }

                              updateComponentProperty(selectedComponent.id, "position.y", newY);
                            }
                          }}
                        />
                      </div>
                    </div>

                    {/* 크기 속성 */}
                    <div className="grid grid-cols-2 gap-4">
                      <div className="space-y-2">
                        <Label htmlFor="width">
                          {layout.gridSettings?.snapToGrid ? "너비 (격자 컬럼)" : "너비 (픽셀)"}
                        </Label>
                        {layout.gridSettings?.snapToGrid && gridInfo ? (
                          // 격자 스냅이 활성화된 경우 컬럼 단위로 조정
                          <div className="space-y-1">
                            <Input
                              id="width"
                              type="number"
                              min="1"
                              max={layout.gridSettings.columns}
                              value={(() => {
                                const { columnWidth } = gridInfo;
                                const { gap } = layout.gridSettings;
                                return Math.max(
                                  1,
                                  Math.round((selectedComponent.size.width + gap) / (columnWidth + gap)),
                                );
                              })()}
                              onChange={(e) => {
                                const gridColumns = Math.max(
                                  1,
                                  Math.min(layout.gridSettings!.columns, parseInt(e.target.value) || 1),
                                );
                                const { columnWidth } = gridInfo;
                                const { gap } = layout.gridSettings!;
                                const newWidth = gridColumns * columnWidth + (gridColumns - 1) * gap;
                                updateComponentProperty(selectedComponent.id, "size.width", newWidth);
                              }}
                            />
                            <div className="text-xs text-gray-500">실제 너비: {selectedComponent.size.width}px</div>
                          </div>
                        ) : (
                          // 격자 스냅이 비활성화된 경우 픽셀 단위로 조정
                          <Input
                            id="width"
                            type="number"
                            min="20"
                            value={selectedComponent.size.width}
                            onChange={(e) => {
                              const val = (e.target as HTMLInputElement).valueAsNumber;
                              if (Number.isFinite(val)) {
                                const newWidth = Math.max(20, Math.round(val));
                                updateComponentProperty(selectedComponent.id, "size.width", newWidth);
                              }
                            }}
                          />
                        )}
                      </div>
                      <div className="space-y-2">
                        <Label htmlFor="height">높이 (픽셀)</Label>
                        <Input
                          id="height"
                          type="number"
                          min="20"
                          value={selectedComponent.size.height}
                          onChange={(e) => {
                            const val = (e.target as HTMLInputElement).valueAsNumber;
                            if (Number.isFinite(val)) {
                              let newHeight = Math.max(20, Math.round(val));

                              // 격자 스냅이 활성화된 경우 20px 단위로 조정
                              if (layout.gridSettings?.snapToGrid) {
                                newHeight = Math.max(40, Math.round(newHeight / 20) * 20);
                              }

                              updateComponentProperty(selectedComponent.id, "size.height", newHeight);
                            }
                          }}
                        />
                      </div>
                    </div>

                    {/* 테이블 정보 */}
                    <Separator />
                    <div className="space-y-2">
                      <Label htmlFor="tableName">테이블명</Label>
                      <Input id="tableName" value={selectedComponent.tableName || ""} readOnly className="bg-muted" />
                    </div>

                    {/* 위젯 전용 속성 */}
                    {selectedComponent.type === "widget" && (
                      <>
                        <div className="space-y-2">
                          <Label htmlFor="columnName">컬럼명</Label>
                          <Input
                            id="columnName"
                            value={selectedComponent.columnName || ""}
                            readOnly
                            className="bg-muted"
                          />
                        </div>
                        <div className="space-y-2">
                          <Label htmlFor="widgetType">위젯 타입</Label>
                          <Input
                            id="widgetType"
                            value={selectedComponent.widgetType || ""}
                            readOnly
                            className="bg-muted"
                          />
                        </div>
                        <div className="space-y-2">
                          <Label htmlFor="widgetLabel">라벨</Label>
                          <Input
                            id="widgetLabel"
                            value={selectedComponent.label || ""}
                            onChange={(e) => updateComponentProperty(selectedComponent.id, "label", e.target.value)}
                          />
                        </div>
                        <div className="space-y-2">
                          <Label htmlFor="widgetPlaceholder">플레이스홀더</Label>
                          <Input
                            id="widgetPlaceholder"
                            value={selectedComponent.placeholder || ""}
                            onChange={(e) =>
                              updateComponentProperty(selectedComponent.id, "placeholder", e.target.value)
                            }
                          />
                        </div>
                        <div className="flex items-center space-x-4">
                          <div className="flex items-center space-x-2">
                            <input
                              type="checkbox"
                              id="required"
                              checked={selectedComponent.required || false}
                              onChange={(e) =>
                                updateComponentProperty(selectedComponent.id, "required", e.target.checked)
                              }
                            />
                            <Label htmlFor="required">필수</Label>
                          </div>
                          <div className="flex items-center space-x-2">
                            <input
                              type="checkbox"
                              id="readonly"
                              checked={selectedComponent.readonly || false}
                              onChange={(e) =>
                                updateComponentProperty(selectedComponent.id, "readonly", e.target.checked)
                              }
                            />
                            <Label htmlFor="readonly">읽기 전용</Label>
                          </div>
                        </div>
                      </>
                    )}

                    {/* 스타일 속성 */}
                    <Separator />
                    <div>
                      <Label className="text-sm font-medium">스타일 편집</Label>
                      <StyleEditor
                        style={selectedComponent.style || {}}
                        onStyleChange={(newStyle) => updateComponentProperty(selectedComponent.id, "style", newStyle)}
                      />
                    </div>

                    {/* 고급 속성 */}
                    <Separator />
                    <div className="space-y-2">
                      <Label htmlFor="parentId">부모 ID</Label>
                      <Input id="parentId" value={selectedComponent.parentId || ""} readOnly className="bg-muted" />
                    </div>
                    <Button variant="destructive" size="sm" onClick={deleteComponents} className="w-full">
                      <Trash2 className="mr-2 h-4 w-4" />
                      {selectedComponent.type === "group"
                        ? "그룹 삭제"
                        : groupState.selectedComponents.length > 1
                          ? `${groupState.selectedComponents.length}개 삭제`
                          : "컴포넌트 삭제"}
                    </Button>
                  </CardContent>
                </Card>
              </div>
            ) : (
              <div className="py-8 text-center text-gray-500">
                <Settings className="mx-auto mb-2 h-12 w-12 text-gray-300" />
                <p>컴포넌트를 선택하여 속성을 편집하세요</p>
              </div>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}
