"use client";

import { useState, useEffect, useMemo } from "react";
import { Button } from "@/components/ui/button";
import { ArrowLeft, Save, Loader2, Grid3x3, Move, Box, Package, Truck } from "lucide-react";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import dynamic from "next/dynamic";
import { useToast } from "@/hooks/use-toast";
import type { PlacedObject, ToolType, Warehouse, Area, Location, ObjectType } from "@/types/digitalTwin";
import {
  getWarehouses,
  getAreas,
  getLocations,
  getLayoutById,
  updateLayout,
  getMaterialCounts,
  getMaterials,
} from "@/lib/api/digitalTwin";
import type { MaterialData } from "@/types/digitalTwin";
import { ExternalDbConnectionAPI } from "@/lib/api/externalDbConnection";

// 백엔드 DB 객체 타입 (snake_case)
interface DbObject {
  id: number;
  object_type: ObjectType;
  object_name: string;
  position_x: string;
  position_y: string;
  position_z: string;
  size_x: string;
  size_y: string;
  size_z: string;
  rotation?: string;
  color: string;
  area_key?: string;
  loca_key?: string;
  loc_type?: string;
  material_count?: number;
  material_preview_height?: string;
  parent_id?: number;
  display_order?: number;
  locked?: boolean;
  visible?: boolean;
}

const Yard3DCanvas = dynamic(() => import("./Yard3DCanvas"), {
  ssr: false,
  loading: () => (
    <div className="bg-muted flex h-full items-center justify-center">
      <Loader2 className="text-muted-foreground h-8 w-8 animate-spin" />
    </div>
  ),
});

interface DigitalTwinEditorProps {
  layoutId: number;
  layoutName: string;
  onBack: () => void;
}

export default function DigitalTwinEditor({ layoutId, layoutName, onBack }: DigitalTwinEditorProps) {
  const { toast } = useToast();
  const [placedObjects, setPlacedObjects] = useState<PlacedObject[]>([]);
  const [selectedObject, setSelectedObject] = useState<PlacedObject | null>(null);
  const [draggedTool, setDraggedTool] = useState<ToolType | null>(null);
  const [draggedAreaData, setDraggedAreaData] = useState<Area | null>(null); // 드래그 중인 Area 정보
  const [draggedLocationData, setDraggedLocationData] = useState<Location | null>(null); // 드래그 중인 Location 정보
  const [isLoading, setIsLoading] = useState(true);
  const [isSaving, setIsSaving] = useState(false);
  const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
  const [externalDbConnections, setExternalDbConnections] = useState<{ id: number; name: string; db_type: string }[]>(
    [],
  );
  const [selectedDbConnection, setSelectedDbConnection] = useState<number | null>(null);
  const [selectedWarehouse, setSelectedWarehouse] = useState<string | null>(null);
  const [warehouses, setWarehouses] = useState<Warehouse[]>([]);
  const [availableAreas, setAvailableAreas] = useState<Area[]>([]);
  const [availableLocations, setAvailableLocations] = useState<Location[]>([]);
  const [nextObjectId, setNextObjectId] = useState(-1);
  const [loadingWarehouses, setLoadingWarehouses] = useState(false);
  const [loadingAreas, setLoadingAreas] = useState(false);
  const [loadingLocations, setLoadingLocations] = useState(false);
  const [materials, setMaterials] = useState<MaterialData[]>([]);
  const [loadingMaterials, setLoadingMaterials] = useState(false);
  const [showMaterialPanel, setShowMaterialPanel] = useState(false);
  
  // 테이블 매핑 관련 상태
  const [availableTables, setAvailableTables] = useState<string[]>([]);
  const [loadingTables, setLoadingTables] = useState(false);
  const [selectedTables, setSelectedTables] = useState({
    warehouse: "",
    area: "",
    location: "",
    material: "",
  });
  const [tableColumns, setTableColumns] = useState<{ [key: string]: string[] }>({});
  const [selectedColumns, setSelectedColumns] = useState({
    warehouseKey: "WAREKEY",
    warehouseName: "WARENAME",
    areaKey: "AREAKEY",
    areaName: "AREANAME",
    locationKey: "LOCAKEY",
    locationName: "LOCANAME",
    materialKey: "STKKEY",
  });

  // placedObjects를 YardPlacement 형식으로 변환 (useMemo로 최적화)
  const placements = useMemo(() => {
    const now = new Date().toISOString(); // 한 번만 생성
    return placedObjects.map((obj) => ({
      id: obj.id,
      yard_layout_id: layoutId,
      material_code: null,
      material_name: obj.name,
      name: obj.name, // 객체 이름 (야드 이름 표시용)
      quantity: null,
      unit: null,
      position_x: obj.position.x,
      position_y: obj.position.y,
      position_z: obj.position.z,
      size_x: obj.size.x,
      size_y: obj.size.y,
      size_z: obj.size.z,
      color: obj.color,
      data_source_type: obj.type,
      data_source_config: null,
      data_binding: null,
      created_at: now, // 고정된 값 사용
      updated_at: now, // 고정된 값 사용
      material_count: obj.materialCount,
      material_preview_height: obj.materialPreview?.height,
    }));
  }, [placedObjects, layoutId]);

  // 외부 DB 연결 목록 로드
  useEffect(() => {
    const loadExternalDbConnections = async () => {
      try {
        const connections = await ExternalDbConnectionAPI.getConnections({ is_active: "Y" });
        console.log("🔍 외부 DB 연결 목록 (is_active=Y):", connections);
        console.log("🔍 연결 ID들:", connections.map(c => c.id));
        setExternalDbConnections(
          connections.map((conn) => ({
            id: conn.id!,
            name: conn.connection_name,
            db_type: conn.db_type,
          })),
        );
      } catch (error) {
        console.error("외부 DB 연결 목록 조회 실패:", error);
        toast({
          variant: "destructive",
          title: "오류",
          description: "외부 DB 연결 목록을 불러오는데 실패했습니다.",
        });
      }
    };

    loadExternalDbConnections();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []); // 컴포넌트 마운트 시 한 번만 실행

  // 외부 DB 선택 시 테이블 목록 로드
  useEffect(() => {
    if (!selectedDbConnection) {
      setAvailableTables([]);
      setSelectedTables({ warehouse: "", area: "", location: "", material: "" });
      return;
    }

    const loadTables = async () => {
      try {
        setLoadingTables(true);
        const { getTables } = await import("@/lib/api/digitalTwin");
        const response = await getTables(selectedDbConnection);
        if (response.success && response.data) {
          const tableNames = response.data.map((t) => t.table_name);
          setAvailableTables(tableNames);
          console.log("📋 테이블 목록:", tableNames);
        }
      } catch (error) {
        console.error("테이블 목록 조회 실패:", error);
        toast({
          variant: "destructive",
          title: "오류",
          description: "테이블 목록을 불러오는데 실패했습니다.",
        });
      } finally {
        setLoadingTables(false);
      }
    };

    loadTables();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [selectedDbConnection]);

  // 테이블 컬럼 로드
  const loadColumnsForTable = async (tableName: string, type: "warehouse" | "area" | "location" | "material") => {
    if (!selectedDbConnection || !tableName) return;

    try {
      const { getTablePreview } = await import("@/lib/api/digitalTwin");
      const response = await getTablePreview(selectedDbConnection, tableName);
      
      console.log(`📊 ${type} 테이블 미리보기:`, response);

      if (response.success && response.data && response.data.length > 0) {
        const columns = Object.keys(response.data[0]);
        setTableColumns(prev => ({ ...prev, [type]: columns }));
        
        // 자동 매핑 시도 (기본값 설정)
        if (type === "warehouse") {
          const keyCol = columns.find(c => c.includes("KEY") || c.includes("ID")) || columns[0];
          const nameCol = columns.find(c => c.includes("NAME") || c.includes("NAM")) || columns[1] || columns[0];
          setSelectedColumns(prev => ({ ...prev, warehouseKey: keyCol, warehouseName: nameCol }));
        }
      } else {
        console.warn(`⚠️ ${tableName} 테이블에 데이터가 없습니다.`);
        toast({
          variant: "default", // destructive 대신 default로 변경 (단순 알림)
          title: "데이터 없음",
          description: `${tableName} 테이블에 데이터가 없습니다.`,
        });
      }
    } catch (error) {
      console.error(`컬럼 로드 실패 (${tableName}):`, error);
    }
  };

  // 외부 DB 선택 시 창고 목록 로드 (테이블이 선택되어 있을 때만)
  useEffect(() => {
    if (!selectedDbConnection || !selectedTables.warehouse) {
      setWarehouses([]);
      setSelectedWarehouse(null);
      return;
    }

    const loadWarehouses = async () => {
      try {
        setLoadingWarehouses(true);
        const response = await getWarehouses(selectedDbConnection, selectedTables.warehouse);
        console.log("📦 창고 API 응답:", response);
        if (response.success && response.data) {
          console.log("📦 창고 데이터:", response.data);
          setWarehouses(response.data);
        } else {
          // 외부 DB 연결이 유효하지 않으면 선택 초기화
          console.warn("외부 DB 연결이 유효하지 않습니다:", selectedDbConnection);
          setSelectedDbConnection(null);
          toast({
            variant: "destructive",
            title: "외부 DB 연결 오류",
            description: "저장된 외부 DB 연결을 찾을 수 없습니다. 다시 선택해주세요.",
          });
        }
      } catch (error: any) {
        console.error("창고 목록 조회 실패:", error);
        // 외부 DB 연결이 존재하지 않으면 선택 초기화
        if (error.response?.status === 500 && error.response?.data?.error?.includes("연결 정보를 찾을 수 없습니다")) {
          setSelectedDbConnection(null);
          toast({
            variant: "destructive",
            title: "외부 DB 연결 오류",
            description: "저장된 외부 DB 연결을 찾을 수 없습니다. 다시 선택해주세요.",
          });
        } else {
          toast({
            variant: "destructive",
            title: "오류",
            description: "창고 목록을 불러오는데 실패했습니다.",
          });
        }
      } finally {
        setLoadingWarehouses(false);
      }
    };

    loadWarehouses();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [selectedDbConnection, selectedTables.warehouse]); // toast 제거, warehouse 테이블 추가

  // 창고 선택 시 Area 목록 로드
  useEffect(() => {
    if (!selectedDbConnection || !selectedWarehouse) {
      setAvailableAreas([]);
      return;
    }

    const loadAreas = async () => {
      try {
        setLoadingAreas(true);
        const response = await getAreas(selectedDbConnection, selectedTables.area, selectedWarehouse);
        if (response.success && response.data) {
          setAvailableAreas(response.data);
        }
      } catch (error) {
        console.error("Area 목록 조회 실패:", error);
        toast({
          variant: "destructive",
          title: "오류",
          description: "Area 목록을 불러오는데 실패했습니다.",
        });
      } finally {
        setLoadingAreas(false);
      }
    };

    loadAreas();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [selectedDbConnection, selectedWarehouse, selectedTables.area]); // toast 제거, area 테이블 추가

  // 레이아웃 데이터 로드
  const [layoutData, setLayoutData] = useState<{ layout: any; objects: any[] } | null>(null);

  useEffect(() => {
    const loadLayout = async () => {
      try {
        setIsLoading(true);
        const response = await getLayoutById(layoutId);

        if (response.success && response.data) {
          const { layout, objects } = response.data;
          setLayoutData({ layout, objects }); // 레이아웃 데이터 저장

          // 객체 데이터 변환 (DB -> PlacedObject)
          const loadedObjects: PlacedObject[] = (objects as unknown as DbObject[]).map((obj) => ({
            id: obj.id,
            type: obj.object_type,
            name: obj.object_name,
            position: {
              x: parseFloat(obj.position_x),
              y: parseFloat(obj.position_y),
              z: parseFloat(obj.position_z),
            },
            size: {
              x: parseFloat(obj.size_x),
              y: parseFloat(obj.size_y),
              z: parseFloat(obj.size_z),
            },
            rotation: obj.rotation ? parseFloat(obj.rotation) : 0,
            color: obj.color,
            areaKey: obj.area_key,
            locaKey: obj.loca_key,
            locType: obj.loc_type,
            materialCount: obj.material_count,
            materialPreview: obj.material_preview_height
              ? { height: parseFloat(obj.material_preview_height) }
              : undefined,
            parentId: obj.parent_id,
            displayOrder: obj.display_order,
            locked: obj.locked,
            visible: obj.visible !== false,
          }));

          setPlacedObjects(loadedObjects);

          // 다음 임시 ID 설정 (기존 ID 중 최소값 - 1)
          const minId = Math.min(...loadedObjects.map((o) => o.id), 0);
          setNextObjectId(minId - 1);

          setHasUnsavedChanges(false);

          toast({
            title: "레이아웃 불러오기 완료",
            description: `${loadedObjects.length}개의 객체를 불러왔습니다.`,
          });

          // Location 객체들의 자재 개수 로드
          const locationObjects = loadedObjects.filter(
            (obj) =>
              (obj.type === "location-bed" ||
                obj.type === "location-stp" ||
                obj.type === "location-temp" ||
                obj.type === "location-dest") &&
              obj.locaKey,
          );
          if (locationObjects.length > 0) {
            const locaKeys = locationObjects.map((obj) => obj.locaKey!);
            setTimeout(() => {
              loadMaterialCountsForLocations(locaKeys);
            }, 100);
          }
        } else {
          throw new Error(response.error || "레이아웃 조회 실패");
        }
      } catch (error) {
        console.error("레이아웃 로드 실패:", error);
        const errorMessage = error instanceof Error ? error.message : "레이아웃을 불러오는데 실패했습니다.";
        toast({
          variant: "destructive",
          title: "오류",
          description: errorMessage,
        });
      } finally {
        setIsLoading(false);
      }
    };

    loadLayout();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [layoutId]); // toast 제거

  // 외부 DB 연결 자동 선택 (externalDbConnections 로드 완료 시)
  useEffect(() => {
    if (!layoutData || !layoutData.layout.externalDbConnectionId || externalDbConnections.length === 0) {
      return;
    }

    const layout = layoutData.layout;
    console.log("🔍 외부 DB 연결 자동 선택 시도");
    console.log("🔍 레이아웃의 externalDbConnectionId:", layout.externalDbConnectionId);
    console.log("🔍 사용 가능한 연결 목록:", externalDbConnections);

    const connectionExists = externalDbConnections.some(
      (conn) => conn.id === layout.externalDbConnectionId,
    );
    console.log("🔍 연결 존재 여부:", connectionExists);

    if (connectionExists) {
      setSelectedDbConnection(layout.externalDbConnectionId);
      if (layout.warehouseKey) {
        setSelectedWarehouse(layout.warehouseKey);
      }
      console.log("✅ 외부 DB 연결 자동 선택 완료:", layout.externalDbConnectionId);
    } else {
      console.warn("⚠️ 저장된 외부 DB 연결을 찾을 수 없습니다:", layout.externalDbConnectionId);
      console.warn("⚠️ 사용 가능한 연결 ID들:", externalDbConnections.map(c => c.id));
      toast({
        variant: "destructive",
        title: "외부 DB 연결 오류",
        description: "저장된 외부 DB 연결을 찾을 수 없습니다. 다시 선택해주세요.",
      });
    }
  }, [layoutData, externalDbConnections]); // layoutData와 externalDbConnections가 모두 준비되면 실행

  // 도구 타입별 기본 설정
  const getToolDefaults = (type: ToolType): Partial<PlacedObject> => {
    switch (type) {
      case "area":
        return {
          name: "영역",
          size: { x: 20, y: 0.1, z: 20 }, // 4x4 칸
          color: "#3b82f6", // 파란색
        };
      case "location-bed":
        return {
          name: "베드(BED)",
          size: { x: 5, y: 2, z: 5 }, // 1x1 칸
          color: "#10b981", // 에메랄드
        };
      case "location-stp":
        return {
          name: "정차포인트(STP)",
          size: { x: 5, y: 0.5, z: 5 }, // 1x1 칸, 낮은 높이
          color: "#f59e0b", // 주황색
        };
      case "location-temp":
        return {
          name: "임시베드(TMP)",
          size: { x: 5, y: 2, z: 5 }, // 베드와 동일
          color: "#10b981", // 베드와 동일
        };
      case "location-dest":
        return {
          name: "지정착지(DES)",
          size: { x: 5, y: 2, z: 5 }, // 베드와 동일
          color: "#10b981", // 베드와 동일
        };
      // case "crane-gantry":
      //   return {
      //     name: "겐트리 크레인",
      //     size: { x: 5, y: 8, z: 5 }, // 1x1 칸
      //     color: "#22c55e", // 녹색
      //   };
      case "crane-mobile":
        return {
          name: "크레인",
          size: { x: 5, y: 6, z: 5 }, // 1x1 칸
          color: "#eab308", // 노란색
        };
      case "rack":
        return {
          name: "랙",
          size: { x: 5, y: 3, z: 5 }, // 1x1 칸
          color: "#a855f7", // 보라색
        };
      // case "material":
      //   return {
      //     name: "자재",
      //     size: { x: 5, y: 2, z: 5 }, // 1x1 칸
      //     color: "#ef4444", // 빨간색
      //   };
    }
  };

  // 도구 드래그 시작
  const handleToolDragStart = (toolType: ToolType) => {
    setDraggedTool(toolType);
  };

  // 캔버스에 드롭
  const handleCanvasDrop = (x: number, z: number) => {
    if (!draggedTool) return;

    const defaults = getToolDefaults(draggedTool);

    // Area는 바닥(y=0.05)에, 다른 객체는 중앙 정렬
    const yPosition = draggedTool === "area" ? 0.05 : (defaults.size?.y || 1) / 2;

    // 외부 DB 데이터에서 드래그한 경우 해당 정보 사용
    let objectName = defaults.name || "새 객체";
    let areaKey: string | undefined = undefined;
    let locaKey: string | undefined = undefined;
    let locType: string | undefined = undefined;

    if (draggedTool === "area" && draggedAreaData) {
      objectName = draggedAreaData.AREANAME;
      areaKey = draggedAreaData.AREAKEY;
    } else if (
      (draggedTool === "location-bed" ||
        draggedTool === "location-stp" ||
        draggedTool === "location-temp" ||
        draggedTool === "location-dest") &&
      draggedLocationData
    ) {
      objectName = draggedLocationData.LOCANAME || draggedLocationData.LOCAKEY;
      areaKey = draggedLocationData.AREAKEY;
      locaKey = draggedLocationData.LOCAKEY;
      locType = draggedLocationData.LOCTYPE;
    }

    const newObject: PlacedObject = {
      id: nextObjectId,
      type: draggedTool,
      name: objectName,
      position: { x, y: yPosition, z },
      size: defaults.size || { x: 5, y: 5, z: 5 },
      color: defaults.color || "#9ca3af",
      areaKey,
      locaKey,
      locType,
    };

    setPlacedObjects((prev) => [...prev, newObject]);
    setSelectedObject(newObject);
    setNextObjectId((prev) => prev - 1);
    setHasUnsavedChanges(true);
    setDraggedTool(null);
    setDraggedAreaData(null);
    setDraggedLocationData(null);

    // Location 배치 시 자재 개수 로드
    if (
      (draggedTool === "location-bed" ||
        draggedTool === "location-stp" ||
        draggedTool === "location-temp" ||
        draggedTool === "location-dest") &&
      locaKey
    ) {
      // 새 객체 추가 후 자재 개수 로드 (약간의 딜레이를 두어 state 업데이트 완료 후 실행)
      setTimeout(() => {
        loadMaterialCountsForLocations();
      }, 100);
    }
  };

  // Location의 자재 목록 로드
  const loadMaterialsForLocation = async (locaKey: string) => {
    if (!selectedDbConnection) return;

    try {
      setLoadingMaterials(true);
      setShowMaterialPanel(true);
      const response = await getMaterials(selectedDbConnection, selectedTables.material, locaKey);
      if (response.success && response.data) {
        // LOLAYER 순으로 정렬
        const sortedMaterials = response.data.sort((a, b) => a.LOLAYER - b.LOLAYER);
        setMaterials(sortedMaterials);
      } else {
        setMaterials([]);
        toast({
          variant: "destructive",
          title: "자재 조회 실패",
          description: response.error || "자재 목록을 불러올 수 없습니다.",
        });
      }
    } catch (error) {
      console.error("자재 로드 실패:", error);
      setMaterials([]);
      toast({
        variant: "destructive",
        title: "오류",
        description: "자재 목록을 불러오는데 실패했습니다.",
      });
    } finally {
      setLoadingMaterials(false);
    }
  };

  // 객체 클릭
  const handleObjectClick = (objectId: number | null) => {
    if (objectId === null) {
      setSelectedObject(null);
      setShowMaterialPanel(false);
      return;
    }

    const obj = placedObjects.find((o) => o.id === objectId);
    setSelectedObject(obj || null);

    // Area를 클릭한 경우, 해당 Area의 Location 목록 로드
    if (obj && obj.type === "area" && obj.areaKey && selectedDbConnection) {
      loadLocationsForArea(obj.areaKey);
      setShowMaterialPanel(false);
    }
    // Location을 클릭한 경우, 해당 Location의 자재 목록 로드
    else if (
      obj &&
      (obj.type === "location-bed" ||
        obj.type === "location-stp" ||
        obj.type === "location-temp" ||
        obj.type === "location-dest") &&
      obj.locaKey &&
      selectedDbConnection
    ) {
      loadMaterialsForLocation(obj.locaKey);
    } else {
      setShowMaterialPanel(false);
    }
  };

  // Location별 자재 개수 로드 (locaKeys를 직접 받음)
  const loadMaterialCountsForLocations = async (locaKeys: string[]) => {
    if (!selectedDbConnection || locaKeys.length === 0) return;

    try {
      const response = await getMaterialCounts(selectedDbConnection, selectedTables.material, locaKeys);
      if (response.success && response.data) {
        // 각 Location 객체에 자재 개수 업데이트
        setPlacedObjects((prev) =>
          prev.map((obj) => {
            const materialCount = response.data?.find((mc) => mc.LOCAKEY === obj.locaKey);
            if (materialCount) {
              return {
                ...obj,
                materialCount: materialCount.material_count,
                materialPreview: {
                  height: materialCount.max_layer * 1.5, // 층당 1.5 높이 (시각적)
                },
              };
            }
            return obj;
          }),
        );
      }
    } catch (error) {
      console.error("자재 개수 로드 실패:", error);
    }
  };

  // 특정 Area의 Location 목록 로드
  const loadLocationsForArea = async (areaKey: string) => {
    if (!selectedDbConnection) return;

    try {
      setLoadingLocations(true);
      const response = await getLocations(selectedDbConnection, selectedTables.location, areaKey);
      if (response.success && response.data) {
        setAvailableLocations(response.data);
        toast({
          title: "Location 로드 완료",
          description: `${response.data.length}개 Location을 불러왔습니다.`,
        });
      }
    } catch (error) {
      console.error("Location 목록 조회 실패:", error);
      toast({
        variant: "destructive",
        title: "오류",
        description: "Location 목록을 불러오는데 실패했습니다.",
      });
    } finally {
      setLoadingLocations(false);
    }
  };

  // 객체 이동
  const handleObjectMove = (objectId: number, newX: number, newZ: number, newY?: number) => {
    // Yard3DCanvas에서 이미 스냅+오프셋이 완료된 좌표를 받음
    // 그대로 저장하면 됨
    setPlacedObjects((prev) =>
      prev.map((obj) => {
        if (obj.id === objectId) {
          const newPosition = { ...obj.position, x: newX, z: newZ };
          if (newY !== undefined) {
            newPosition.y = newY;
          }
          return { ...obj, position: newPosition };
        }
        return obj;
      }),
    );

    if (selectedObject?.id === objectId) {
      setSelectedObject((prev) => {
        if (!prev) return null;
        const newPosition = { ...prev.position, x: newX, z: newZ };
        if (newY !== undefined) {
          newPosition.y = newY;
        }
        return { ...prev, position: newPosition };
      });
    }

    setHasUnsavedChanges(true);
  };

  // 객체 속성 업데이트
  const handleObjectUpdate = (updates: Partial<PlacedObject>) => {
    if (!selectedObject) return;

    let finalUpdates = { ...updates };

    // 크기 변경 시에만 5 단위로 스냅하고 위치 조정 (position 변경은 제외)
    if (updates.size && !updates.position) {
      // placedObjects 배열에서 실제 저장된 객체를 가져옴 (selectedObject 상태가 아닌)
      const actualObject = placedObjects.find((obj) => obj.id === selectedObject.id);
      if (!actualObject) return;

      const oldSize = actualObject.size;
      const newSize = { ...oldSize, ...updates.size };

      // W, D를 5 단위로 스냅
      newSize.x = Math.max(5, Math.round(newSize.x / 5) * 5);
      newSize.z = Math.max(5, Math.round(newSize.z / 5) * 5);

      // H는 자유롭게 (Area 제외)
      if (actualObject.type !== "area") {
        newSize.y = Math.max(0.1, newSize.y);
      }

      // 크기 차이 계산
      const deltaX = newSize.x - oldSize.x;
      const deltaZ = newSize.z - oldSize.z;
      const deltaY = newSize.y - oldSize.y;

      // 위치 조정: 왼쪽/뒤쪽/바닥 모서리 고정, 오른쪽/앞쪽/위쪽으로만 늘어남
      // Three.js는 중심점 기준이므로 크기 차이의 절반만큼 위치 이동
      // actualObject.position (실제 배열의 position)을 기준으로 계산
      const newPosition = {
        ...actualObject.position,
        x: actualObject.position.x + deltaX / 2, // 오른쪽으로 늘어남
        y: actualObject.position.y + deltaY / 2, // 위쪽으로 늘어남 (바닥 고정)
        z: actualObject.position.z + deltaZ / 2, // 앞쪽으로 늘어남
      };

      finalUpdates = {
        ...finalUpdates,
        size: newSize,
        position: newPosition,
      };
    }

    setPlacedObjects((prev) => prev.map((obj) => (obj.id === selectedObject.id ? { ...obj, ...finalUpdates } : obj)));

    setSelectedObject((prev) => (prev ? { ...prev, ...finalUpdates } : null));
    setHasUnsavedChanges(true);
  };

  // 객체 삭제
  const handleObjectDelete = () => {
    if (!selectedObject) return;

    setPlacedObjects((prev) => prev.filter((obj) => obj.id !== selectedObject.id));
    setSelectedObject(null);
    setHasUnsavedChanges(true);
  };

  // 저장
  const handleSave = async () => {
    if (!selectedDbConnection) {
      toast({
        title: "외부 DB 선택 필요",
        description: "외부 데이터베이스 연결을 선택하세요.",
        variant: "destructive",
      });
      return;
    }

    if (!selectedWarehouse) {
      toast({
        title: "창고 선택 필요",
        description: "창고를 선택하세요.",
        variant: "destructive",
      });
      return;
    }

    setIsSaving(true);
    try {
      const response = await updateLayout(layoutId, {
        layoutName: layoutName,
        description: undefined,
        objects: placedObjects.map((obj, index) => ({
          ...obj,
          displayOrder: index, // 현재 순서대로 저장
        })),
      });

      if (response.success) {
        toast({
          title: "저장 완료",
          description: `${placedObjects.length}개의 객체가 저장되었습니다.`,
        });

        setHasUnsavedChanges(false);

        // 저장 후 DB에서 할당된 ID로 객체 업데이트 (필요 시)
        // 현재는 updateLayout이 기존 객체 삭제 후 재생성하므로
        // 레이아웃 다시 불러오기
        const reloadResponse = await getLayoutById(layoutId);
        if (reloadResponse.success && reloadResponse.data) {
          const { objects } = reloadResponse.data;
          const reloadedObjects: PlacedObject[] = (objects as unknown as DbObject[]).map((obj) => ({
            id: obj.id,
            type: obj.object_type,
            name: obj.object_name,
            position: {
              x: parseFloat(obj.position_x),
              y: parseFloat(obj.position_y),
              z: parseFloat(obj.position_z),
            },
            size: {
              x: parseFloat(obj.size_x),
              y: parseFloat(obj.size_y),
              z: parseFloat(obj.size_z),
            },
            rotation: obj.rotation ? parseFloat(obj.rotation) : 0,
            color: obj.color,
            areaKey: obj.area_key,
            locaKey: obj.loca_key,
            locType: obj.loc_type,
            materialCount: obj.material_count,
            materialPreview: obj.material_preview_height
              ? { height: parseFloat(obj.material_preview_height) }
              : undefined,
            parentId: obj.parent_id,
            displayOrder: obj.display_order,
            locked: obj.locked,
            visible: obj.visible !== false,
          }));

          setPlacedObjects(reloadedObjects);
        }
      } else {
        throw new Error(response.error || "레이아웃 저장 실패");
      }
    } catch (error) {
      console.error("저장 실패:", error);
      const errorMessage = error instanceof Error ? error.message : "레이아웃 저장에 실패했습니다.";
      toast({
        title: "저장 실패",
        description: errorMessage,
        variant: "destructive",
      });
    } finally {
      setIsSaving(false);
    }
  };

  return (
    <div className="bg-background flex h-full flex-col">
      {/* 상단 툴바 */}
      <div className="flex items-center justify-between border-b p-4">
        <div className="flex items-center gap-4">
          <Button variant="ghost" size="sm" onClick={onBack}>
            <ArrowLeft className="mr-2 h-4 w-4" />
            목록으로
          </Button>
          <div>
            <h2 className="text-lg font-semibold">{layoutName}</h2>
            <p className="text-muted-foreground text-sm">디지털 트윈 야드 편집</p>
          </div>
        </div>

        <div className="flex items-center gap-2">
          {hasUnsavedChanges && <span className="text-warning text-sm font-medium">미저장 변경사항 있음</span>}
          <Button size="sm" onClick={handleSave} disabled={isSaving || !hasUnsavedChanges}>
            {isSaving ? (
              <>
                <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                저장 중...
              </>
            ) : (
              <>
                <Save className="mr-2 h-4 w-4" />
                저장
              </>
            )}
          </Button>
        </div>
      </div>

      {/* 도구 팔레트 */}
      <div className="bg-muted flex items-center justify-center gap-2 border-b p-4">
        <span className="text-muted-foreground text-sm font-medium">도구:</span>
        {[
          { type: "area" as ToolType, label: "영역", icon: Grid3x3, color: "text-blue-500" },
          { type: "location-bed" as ToolType, label: "베드", icon: Package, color: "text-emerald-500" },
          { type: "location-stp" as ToolType, label: "정차", icon: Move, color: "text-orange-500" },
          // { type: "crane-gantry" as ToolType, label: "겐트리", icon: Combine, color: "text-green-500" },
          { type: "crane-mobile" as ToolType, label: "크레인", icon: Truck, color: "text-yellow-500" },
          { type: "rack" as ToolType, label: "랙", icon: Box, color: "text-purple-500" },
        ].map((tool) => {
          const Icon = tool.icon;
          return (
            <div
              key={tool.type}
              draggable
              onDragStart={() => handleToolDragStart(tool.type)}
              className="bg-background hover:bg-accent flex cursor-grab items-center gap-1 rounded-md border px-3 py-2 transition-colors active:cursor-grabbing"
              title={`${tool.label} 드래그하여 배치`}
            >
              <Icon className={`h-4 w-4 ${tool.color}`} />
              <span className="text-xs">{tool.label}</span>
            </div>
          );
        })}
      </div>

      {/* 메인 영역 */}
      <div className="flex flex-1 overflow-hidden">
        {/* 좌측: 외부 DB 선택 + 객체 목록 */}
        <div className="flex h-full w-[20%] flex-col border-r">
          {/* 스크롤 영역 */}
          <div className="flex-1 overflow-y-auto p-4 space-y-6">
            {/* 외부 DB 선택 */}
            <div>
              <Label className="mb-2 block text-sm font-semibold">외부 데이터베이스</Label>
              <Select
                value={selectedDbConnection?.toString() || ""}
                onValueChange={(value) => {
                  setSelectedDbConnection(parseInt(value));
                  setSelectedWarehouse(null);
                  setHasUnsavedChanges(true);
                }}
              >
                <SelectTrigger className="h-10 text-sm">
                  <SelectValue placeholder="DB 선택..." />
                </SelectTrigger>
                <SelectContent>
                  {externalDbConnections.map((conn) => (
                    <SelectItem key={conn.id} value={conn.id.toString()} className="text-sm">
                      {conn.name}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>

            {/* 테이블 매핑 선택 */}
            {selectedDbConnection && (
              <div className="space-y-3">
                <Label className="text-sm font-semibold">테이블 매핑 설정</Label>
                {loadingTables ? (
                  <div className="flex h-20 items-center justify-center">
                    <Loader2 className="text-muted-foreground h-4 w-4 animate-spin" />
                  </div>
                ) : (
                  <>
                    <div>
                      <Label className="text-muted-foreground mb-1 block text-xs">창고 테이블</Label>
                      <Select
                        value={selectedTables.warehouse}
                        onValueChange={(value) => {
                          setSelectedTables({ ...selectedTables, warehouse: value });
                          loadColumnsForTable(value, "warehouse");
                          setHasUnsavedChanges(true);
                        }}
                      >
                        <SelectTrigger className="h-9 text-xs">
                          <SelectValue placeholder="테이블 선택..." />
                        </SelectTrigger>
                        <SelectContent>
                          {availableTables.map((table) => (
                            <SelectItem key={table} value={table} className="text-xs">
                              {table}
                            </SelectItem>
                          ))}
                        </SelectContent>
                      </Select>
                    </div>

                    {/* 창고 컬럼 매핑 */}
                    {selectedTables.warehouse && tableColumns.warehouse && (
                      <div className="ml-2 space-y-2 border-l-2 pl-2">
                        <div>
                          <Label className="text-muted-foreground mb-1 block text-[10px]">ID 컬럼</Label>
                          <Select
                            value={selectedColumns.warehouseKey}
                            onValueChange={(value) => setSelectedColumns({ ...selectedColumns, warehouseKey: value })}
                          >
                            <SelectTrigger className="h-7 text-[10px]">
                              <SelectValue />
                            </SelectTrigger>
                            <SelectContent>
                              {tableColumns.warehouse.map((col) => (
                                <SelectItem key={col} value={col} className="text-xs">{col}</SelectItem>
                              ))}
                            </SelectContent>
                          </Select>
                        </div>
                        <div>
                          <Label className="text-muted-foreground mb-1 block text-[10px]">이름 컬럼</Label>
                          <Select
                            value={selectedColumns.warehouseName}
                            onValueChange={(value) => setSelectedColumns({ ...selectedColumns, warehouseName: value })}
                          >
                            <SelectTrigger className="h-7 text-[10px]">
                              <SelectValue />
                            </SelectTrigger>
                            <SelectContent>
                              {tableColumns.warehouse.map((col) => (
                                <SelectItem key={col} value={col} className="text-xs">{col}</SelectItem>
                              ))}
                            </SelectContent>
                          </Select>
                        </div>
                      </div>
                    )}

                    <div>
                      <Label className="text-muted-foreground mb-1 block text-xs">상위 영역 테이블 (예: Area)</Label>
                      <Select
                        value={selectedTables.area}
                        onValueChange={(value) => {
                          setSelectedTables({ ...selectedTables, area: value });
                          loadColumnsForTable(value, "area");
                          setHasUnsavedChanges(true);
                        }}
                      >
                        <SelectTrigger className="h-9 text-xs">
                          <SelectValue placeholder="테이블 선택..." />
                        </SelectTrigger>
                        <SelectContent>
                          {availableTables.map((table) => (
                            <SelectItem key={table} value={table} className="text-xs">
                              {table}
                            </SelectItem>
                          ))}
                        </SelectContent>
                      </Select>
                    </div>

                    <div>
                      <Label className="text-muted-foreground mb-1 block text-xs">하위 영역 테이블 (예: Location)</Label>
                      <Select
                        value={selectedTables.location}
                        onValueChange={(value) => {
                          setSelectedTables({ ...selectedTables, location: value });
                          loadColumnsForTable(value, "location");
                          setHasUnsavedChanges(true);
                        }}
                      >
                        <SelectTrigger className="h-9 text-xs">
                          <SelectValue placeholder="테이블 선택..." />
                        </SelectTrigger>
                        <SelectContent>
                          {availableTables.map((table) => (
                            <SelectItem key={table} value={table} className="text-xs">
                              {table}
                            </SelectItem>
                          ))}
                        </SelectContent>
                      </Select>
                    </div>

                    <div>
                      <Label className="text-muted-foreground mb-1 block text-xs">자재 테이블</Label>
                      <Select
                        value={selectedTables.material}
                        onValueChange={(value) => {
                          setSelectedTables({ ...selectedTables, material: value });
                          loadColumnsForTable(value, "material");
                          setHasUnsavedChanges(true);
                        }}
                      >
                        <SelectTrigger className="h-9 text-xs">
                          <SelectValue placeholder="테이블 선택..." />
                        </SelectTrigger>
                        <SelectContent>
                          {availableTables.map((table) => (
                            <SelectItem key={table} value={table} className="text-xs">
                              {table}
                            </SelectItem>
                          ))}
                        </SelectContent>
                      </Select>
                    </div>
                  </>
                )}
              </div>
            )}

            {/* 창고 선택 */}
            {selectedDbConnection && selectedTables.warehouse && (
              <div>
                <Label className="mb-2 block text-sm font-semibold">창고</Label>
                {loadingWarehouses ? (
                  <div className="flex h-10 items-center justify-center">
                    <Loader2 className="text-muted-foreground h-4 w-4 animate-spin" />
                  </div>
                ) : (
                  <Select
                    value={selectedWarehouse || ""}
                    onValueChange={(value) => {
                      setSelectedWarehouse(value);
                      setHasUnsavedChanges(true);
                    }}
                  >
                    <SelectTrigger className="h-10 text-sm">
                      <SelectValue placeholder="창고 선택..." />
                    </SelectTrigger>
                    <SelectContent>
                      {warehouses.map((wh: any) => (
                        <SelectItem 
                          key={wh[selectedColumns.warehouseKey] || wh.WAREKEY} 
                          value={wh[selectedColumns.warehouseKey] || wh.WAREKEY} 
                          className="text-sm"
                        >
                          {wh[selectedColumns.warehouseName] || wh.WARENAME || wh[selectedColumns.warehouseKey] || wh.WAREKEY}
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                )}
              </div>
            )}

            {/* Area 목록 */}
            {selectedDbConnection && selectedWarehouse && (
              <div className="space-y-3">
                <div className="flex items-center justify-between">
                  <h4 className="text-sm font-semibold">사용 가능한 Area</h4>
                  {loadingAreas && <Loader2 className="text-muted-foreground h-3 w-3 animate-spin" />}
                </div>

                {availableAreas.length === 0 ? (
                  <p className="text-muted-foreground text-xs">Area가 없습니다</p>
                ) : (
                  <div className="space-y-2">
                    {availableAreas.map((area) => (
                      <div
                        key={area.AREAKEY}
                        draggable
                        onDragStart={() => {
                          // Area 정보를 임시 저장
                          setDraggedTool("area");
                          setDraggedAreaData(area);
                        }}
                        onDragEnd={() => {
                          setDraggedAreaData(null);
                        }}
                        className="bg-background hover:bg-accent cursor-grab rounded-lg border p-3 transition-all active:cursor-grabbing"
                      >
                        <div className="flex items-center justify-between">
                          <div className="flex-1">
                            <p className="text-sm font-medium">{area.AREANAME}</p>
                            <p className="text-muted-foreground text-xs">{area.AREAKEY}</p>
                          </div>
                          <Grid3x3 className="text-muted-foreground h-4 w-4" />
                        </div>
                      </div>
                    ))}
                  </div>
                )}
              </div>
            )}

            {/* Location 목록 (Area 클릭 시 표시) */}
            {availableLocations.length > 0 && (
              <div className="space-y-3 border-t pt-4">
                <div className="flex items-center justify-between">
                  <h4 className="text-sm font-semibold">사용 가능한 Location</h4>
                  {loadingLocations && <Loader2 className="text-muted-foreground h-3 w-3 animate-spin" />}
                </div>

                <div className="space-y-2">
                  {availableLocations.map((location) => {
                    // Location 타입에 따라 ObjectType 결정
                    let locationType: ToolType = "location-bed";
                    if (location.LOCTYPE === "STP") {
                      locationType = "location-stp";
                    } else if (location.LOCTYPE === "TMP") {
                      locationType = "location-temp";
                    } else if (location.LOCTYPE === "DES") {
                      locationType = "location-dest";
                    }

                    return (
                      <div
                        key={location.LOCAKEY}
                        draggable
                        onDragStart={() => {
                          // Location 정보를 임시 저장
                          setDraggedTool(locationType);
                          setDraggedLocationData(location);
                        }}
                        onDragEnd={() => {
                          setDraggedLocationData(null);
                        }}
                        className="bg-background hover:bg-accent cursor-grab rounded-lg border p-3 transition-all active:cursor-grabbing"
                      >
                        <div className="flex items-center justify-between">
                          <div className="flex-1">
                            <p className="text-sm font-medium">{location.LOCANAME || location.LOCAKEY}</p>
                            <div className="text-muted-foreground mt-1 flex items-center gap-2 text-xs">
                              <span>{location.LOCAKEY}</span>
                              <span className="bg-muted rounded px-1.5 py-0.5">{location.LOCTYPE}</span>
                            </div>
                          </div>
                          <Package className="text-muted-foreground h-4 w-4" />
                        </div>
                      </div>
                    );
                  })}
                </div>
              </div>
            )}
          </div>

          {/* 배치된 객체 목록 */}
          <div className="flex-1 overflow-y-auto p-4">
            <h3 className="mb-3 text-sm font-semibold">배치된 객체 ({placedObjects.length})</h3>

            {placedObjects.length === 0 ? (
              <div className="text-muted-foreground text-center text-sm">상단 도구를 드래그하여 배치하세요</div>
            ) : (
              <div className="space-y-2">
                {placedObjects.map((obj) => (
                  <div
                    key={obj.id}
                    onClick={() => handleObjectClick(obj.id)}
                    className={`cursor-pointer rounded-lg border p-3 transition-all ${
                      selectedObject?.id === obj.id ? "border-primary bg-primary/10" : "hover:border-primary/50"
                    }`}
                  >
                    <div className="flex items-center justify-between">
                      <span className="text-sm font-medium">{obj.name}</span>
                      <div className="h-3 w-3 rounded-full" style={{ backgroundColor: obj.color }} />
                    </div>
                    <p className="text-muted-foreground mt-1 text-xs">
                      위치: ({obj.position.x.toFixed(1)}, {obj.position.z.toFixed(1)})
                    </p>
                    {obj.areaKey && <p className="text-muted-foreground mt-1 text-xs">Area: {obj.areaKey}</p>}
                  </div>
                ))}
              </div>
            )}
          </div>
        </div>

        {/* 중앙: 3D 캔버스 */}
        <div
          className="h-full flex-1 bg-gray-100"
          onDragOver={(e) => e.preventDefault()}
          onDrop={(e) => {
            e.preventDefault();
            const rect = e.currentTarget.getBoundingClientRect();
            const rawX = ((e.clientX - rect.left) / rect.width - 0.5) * 100;
            const rawZ = ((e.clientY - rect.top) / rect.height - 0.5) * 100;

            // 그리드 크기 (5 단위)
            const gridSize = 5;

            // 그리드에 스냅
            // Area(20x20)는 그리드 교차점에, 다른 객체(5x5)는 타일 중앙에
            let snappedX = Math.round(rawX / gridSize) * gridSize;
            let snappedZ = Math.round(rawZ / gridSize) * gridSize;

            // 5x5 객체는 타일 중앙으로 오프셋 (Area는 제외)
            if (draggedTool !== "area") {
              snappedX += gridSize / 2;
              snappedZ += gridSize / 2;
            }

            handleCanvasDrop(snappedX, snappedZ);
          }}
        >
          {isLoading ? (
            <div className="flex h-full items-center justify-center">
              <Loader2 className="text-muted-foreground h-8 w-8 animate-spin" />
            </div>
          ) : (
            <Yard3DCanvas
              placements={placements}
              selectedPlacementId={selectedObject?.id || null}
              onPlacementClick={(placement) => handleObjectClick(placement?.id || null)}
              onPlacementDrag={(id, position) => handleObjectMove(id, position.x, position.z, position.y)}
              focusOnPlacementId={null}
              onCollisionDetected={() => {}}
            />
          )}
        </div>

        {/* 우측: 객체 속성 편집 or 자재 목록 */}
        <div className="h-full w-[25%] overflow-y-auto border-l">
          {showMaterialPanel && selectedObject ? (
            /* 자재 목록 패널 */
            <div className="p-4">
              <div className="mb-4 flex items-center justify-between">
                <div>
                  <h3 className="text-lg font-semibold">자재 목록</h3>
                  <p className="text-muted-foreground text-xs">
                    {selectedObject.name} ({selectedObject.locaKey})
                  </p>
                </div>
                <Button variant="ghost" size="sm" onClick={() => setShowMaterialPanel(false)}>
                  닫기
                </Button>
              </div>

              {loadingMaterials ? (
                <div className="flex h-32 items-center justify-center">
                  <Loader2 className="text-muted-foreground h-6 w-6 animate-spin" />
                </div>
              ) : materials.length === 0 ? (
                <div className="text-muted-foreground flex h-32 items-center justify-center text-sm">
                  자재가 없습니다
                </div>
              ) : (
                <div className="space-y-2">
                  {materials.map((material, index) => (
                    <div
                      key={`${material.STKKEY}-${index}`}
                      className="bg-muted hover:bg-accent rounded-lg border p-3 transition-colors"
                    >
                      <div className="mb-2 flex items-start justify-between">
                        <div className="flex-1">
                          <p className="text-sm font-medium">{material.STKKEY}</p>
                          <p className="text-muted-foreground mt-0.5 text-xs">
                            층: {material.LOLAYER} | Area: {material.AREAKEY}
                          </p>
                        </div>
                      </div>
                      <div className="text-muted-foreground grid grid-cols-2 gap-2 text-xs">
                        {material.STKWIDT && (
                          <div>
                            폭: <span className="font-medium">{material.STKWIDT}</span>
                          </div>
                        )}
                        {material.STKLENG && (
                          <div>
                            길이: <span className="font-medium">{material.STKLENG}</span>
                          </div>
                        )}
                        {material.STKHEIG && (
                          <div>
                            높이: <span className="font-medium">{material.STKHEIG}</span>
                          </div>
                        )}
                        {material.STKWEIG && (
                          <div>
                            무게: <span className="font-medium">{material.STKWEIG}</span>
                          </div>
                        )}
                      </div>
                      {material.STKRMKS && (
                        <p className="text-muted-foreground mt-2 text-xs italic">{material.STKRMKS}</p>
                      )}
                    </div>
                  ))}
                </div>
              )}
            </div>
          ) : selectedObject ? (
            <div className="p-4">
              <h3 className="mb-4 text-lg font-semibold">객체 속성</h3>

              <div className="space-y-4">
                {/* 이름 */}
                <div>
                  <Label htmlFor="object-name" className="text-sm">
                    이름
                  </Label>
                  <Input
                    id="object-name"
                    value={selectedObject.name}
                    onChange={(e) => handleObjectUpdate({ name: e.target.value })}
                    className="mt-1.5 h-9 text-sm"
                  />
                </div>

                {/* 위치 */}
                <div>
                  <Label className="text-sm">위치</Label>
                  <div className="mt-1.5 grid grid-cols-2 gap-2">
                    <div>
                      <Label htmlFor="pos-x" className="text-muted-foreground text-xs">
                        X
                      </Label>
                      <Input
                        id="pos-x"
                        type="number"
                        value={selectedObject.position.x.toFixed(1)}
                        onChange={(e) =>
                          handleObjectUpdate({
                            position: {
                              ...selectedObject.position,
                              x: parseFloat(e.target.value),
                            },
                          })
                        }
                        className="h-9 text-sm"
                      />
                    </div>
                    <div>
                      <Label htmlFor="pos-z" className="text-muted-foreground text-xs">
                        Z
                      </Label>
                      <Input
                        id="pos-z"
                        type="number"
                        value={selectedObject.position.z.toFixed(1)}
                        onChange={(e) =>
                          handleObjectUpdate({
                            position: {
                              ...selectedObject.position,
                              z: parseFloat(e.target.value),
                            },
                          })
                        }
                        className="h-9 text-sm"
                      />
                    </div>
                  </div>
                </div>

                {/* 크기 */}
                <div>
                  <Label className="text-sm">크기</Label>
                  <div className="mt-1.5 grid grid-cols-3 gap-2">
                    <div>
                      <Label htmlFor="size-x" className="text-muted-foreground text-xs">
                        W (5 단위)
                      </Label>
                      <Input
                        id="size-x"
                        type="number"
                        step="5"
                        min="5"
                        value={selectedObject.size.x}
                        onChange={(e) =>
                          handleObjectUpdate({
                            size: {
                              ...selectedObject.size,
                              x: parseFloat(e.target.value),
                            },
                          })
                        }
                        className="h-9 text-sm"
                      />
                    </div>
                    <div>
                      <Label htmlFor="size-y" className="text-muted-foreground text-xs">
                        H
                      </Label>
                      <Input
                        id="size-y"
                        type="number"
                        value={selectedObject.size.y}
                        onChange={(e) =>
                          handleObjectUpdate({
                            size: {
                              ...selectedObject.size,
                              y: parseFloat(e.target.value),
                            },
                          })
                        }
                        className="h-9 text-sm"
                      />
                    </div>
                    <div>
                      <Label htmlFor="size-z" className="text-muted-foreground text-xs">
                        D (5 단위)
                      </Label>
                      <Input
                        id="size-z"
                        type="number"
                        step="5"
                        min="5"
                        value={selectedObject.size.z}
                        onChange={(e) =>
                          handleObjectUpdate({
                            size: {
                              ...selectedObject.size,
                              z: parseFloat(e.target.value),
                            },
                          })
                        }
                        className="h-9 text-sm"
                      />
                    </div>
                  </div>
                </div>

                {/* 색상 */}
                <div>
                  <Label htmlFor="object-color" className="text-sm">
                    색상
                  </Label>
                  <Input
                    id="object-color"
                    type="color"
                    value={selectedObject.color}
                    onChange={(e) => handleObjectUpdate({ color: e.target.value })}
                    className="mt-1.5 h-9"
                  />
                </div>

                {/* 삭제 버튼 */}
                <Button variant="destructive" size="sm" onClick={handleObjectDelete} className="w-full">
                  객체 삭제
                </Button>
              </div>
            </div>
          ) : (
            <div className="flex h-full items-center justify-center p-4 text-center">
              <p className="text-muted-foreground text-sm">객체를 선택하면 속성을 편집할 수 있습니다</p>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}
