"use client";

import { useState, useEffect, useMemo, useRef } from "react";
import { Loader2, Search, X, Grid3x3, Package, ParkingCircle, RefreshCw, Maximize, Minimize } from "lucide-react";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Button } from "@/components/ui/button";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import dynamic from "next/dynamic";
import { useToast } from "@/hooks/use-toast";
import type { PlacedObject, MaterialData } from "@/types/digitalTwin";
import { getLayoutById, getMaterials } from "@/lib/api/digitalTwin";
import { OBJECT_COLORS, DEFAULT_COLOR } from "./constants";
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";
import { apiCall } from "@/lib/api/client";

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 DigitalTwinViewerProps {
  layoutId: number;
}

// 외부 업체 역할 코드
const EXTERNAL_VENDOR_ROLE = "LSTHIRA_EXTERNAL_VENDOR";

export default function DigitalTwinViewer({ layoutId }: DigitalTwinViewerProps) {
  const { toast } = useToast();
  const [placedObjects, setPlacedObjects] = useState<PlacedObject[]>([]);
  const [selectedObject, setSelectedObject] = useState<PlacedObject | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [materials, setMaterials] = useState<MaterialData[]>([]);
  const [loadingMaterials, setLoadingMaterials] = useState(false);
  const [showInfoPanel, setShowInfoPanel] = useState(false);
  const [externalDbConnectionId, setExternalDbConnectionId] = useState<number | null>(null);
  const [layoutName, setLayoutName] = useState<string>("");
  const [hierarchyConfig, setHierarchyConfig] = useState<any>(null);

  // 검색 및 필터
  const [searchQuery, setSearchQuery] = useState("");
  const [filterType, setFilterType] = useState<string>("all");
  const [isRefreshing, setIsRefreshing] = useState(false);

  // 외부 업체 모드
  const [isExternalMode, setIsExternalMode] = useState(false);
  const [isFullscreen, setIsFullscreen] = useState(false);
  const [layoutKey, setLayoutKey] = useState(0); // 레이아웃 강제 리렌더링용
  const [lastRefreshedAt, setLastRefreshedAt] = useState<Date | null>(null); // 마지막 갱신 시간
  const canvasContainerRef = useRef<HTMLDivElement>(null);

  // 외부 업체 역할 체크
  useEffect(() => {
    const checkExternalRole = async () => {
      try {
        const response = await apiCall<any[]>("GET", "/roles/user/my-groups");
        console.log("=== 사용자 권한 그룹 조회 ===");
        console.log("API 응답:", response);
        console.log("찾는 역할:", EXTERNAL_VENDOR_ROLE);

        if (response.success && response.data) {
          console.log("권한 그룹 목록:", response.data);

          // 사용자의 권한 그룹 중 LSTHIRA_EXTERNAL_VENDOR가 있는지 확인
          const hasExternalRole = response.data.some((group: any) => {
            console.log("체크 중인 그룹:", group.authCode, group.authName);
            return group.authCode === EXTERNAL_VENDOR_ROLE || group.authName === EXTERNAL_VENDOR_ROLE;
          });

          console.log("외부 업체 역할 보유:", hasExternalRole);
          setIsExternalMode(hasExternalRole);
        }
      } catch (error) {
        console.error("역할 조회 실패:", error);
      }
    };

    checkExternalRole();
  }, []);

  // 전체 화면 토글 (3D 캔버스 영역만)
  const toggleFullscreen = () => {
    if (!document.fullscreenElement) {
      // 3D 캔버스 컨테이너만 풀스크린
      canvasContainerRef.current?.requestFullscreen();
      setIsFullscreen(true);
    } else {
      document.exitFullscreen();
      setIsFullscreen(false);
    }
  };

  // 전체 화면 변경 감지
  useEffect(() => {
    const handleFullscreenChange = () => {
      const isNowFullscreen = !!document.fullscreenElement;
      setIsFullscreen(isNowFullscreen);

      // 전체화면 종료 시 레이아웃 강제 리렌더링
      if (!isNowFullscreen) {
        setTimeout(() => {
          setLayoutKey((prev) => prev + 1);
          window.dispatchEvent(new Event("resize"));
        }, 50);
      }
    };

    document.addEventListener("fullscreenchange", handleFullscreenChange);
    return () => document.removeEventListener("fullscreenchange", handleFullscreenChange);
  }, []);

  // 레이아웃 데이터 로드 함수
  const loadLayout = async () => {
    try {
      setIsLoading(true);
      const response = await getLayoutById(layoutId);

      if (response.success && response.data) {
        const { layout, objects } = response.data;

        // 레이아웃 정보 저장 (snake_case와 camelCase 모두 지원)
        setLayoutName(layout.layout_name || layout.layoutName);
        const dbConnectionId = layout.external_db_connection_id || layout.externalDbConnectionId;
        setExternalDbConnectionId(dbConnectionId);

        // hierarchy_config 저장
        let hierarchyConfigData: any = null;
        if (layout.hierarchy_config) {
          hierarchyConfigData =
            typeof layout.hierarchy_config === "string" ? JSON.parse(layout.hierarchy_config) : layout.hierarchy_config;
          setHierarchyConfig(hierarchyConfigData);
        }

        // 객체 데이터 변환
        const loadedObjects: PlacedObject[] = objects.map((obj: any) => {
          const objectType = obj.object_type;
          return {
            id: obj.id,
            type: objectType,
            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: getObjectColor(objectType, obj.color), // 저장된 색상 우선, 없으면 타입별 기본 색상
            areaKey: obj.area_key,
            locaKey: obj.loca_key,
            locType: obj.loc_type,
            materialCount: obj.loc_type === "STP" ? undefined : obj.material_count,
            materialPreview:
              obj.loc_type === "STP" || !obj.material_preview_height
                ? undefined
                : { height: parseFloat(obj.material_preview_height) },
            parentId: obj.parent_id,
            displayOrder: obj.display_order,
            locked: obj.locked,
            visible: obj.visible !== false,
            hierarchyLevel: obj.hierarchy_level,
            parentKey: obj.parent_key,
            externalKey: obj.external_key,
          };
        });

        setPlacedObjects(loadedObjects);

        // 외부 DB 연결이 있고 자재 설정이 있으면, 각 Location의 실제 자재 개수 조회
        if (dbConnectionId && hierarchyConfigData?.material) {
          const locationObjects = loadedObjects.filter(
            (obj) =>
              (obj.type === "location-bed" || obj.type === "location-temp" || obj.type === "location-dest") &&
              obj.locaKey,
          );

          // 각 Location에 대해 자재 개수 조회 (병렬 처리)
          const materialCountPromises = locationObjects.map(async (obj) => {
            try {
              const matResponse = await getMaterials(dbConnectionId, {
                tableName: hierarchyConfigData.material.tableName,
                keyColumn: hierarchyConfigData.material.keyColumn,
                locationKeyColumn: hierarchyConfigData.material.locationKeyColumn,
                layerColumn: hierarchyConfigData.material.layerColumn,
                locaKey: obj.locaKey!,
              });
              if (matResponse.success && matResponse.data) {
                return { id: obj.id, count: matResponse.data.length };
              }
            } catch (e) {
              console.warn(`자재 개수 조회 실패 (${obj.locaKey}):`, e);
            }
            return { id: obj.id, count: 0 };
          });

          const materialCounts = await Promise.all(materialCountPromises);

          // materialCount 업데이트
          setPlacedObjects((prev) =>
            prev.map((obj) => {
              const countData = materialCounts.find((m) => m.id === obj.id);
              if (countData && countData.count > 0) {
                return { ...obj, materialCount: countData.count };
              }
              return obj;
            }),
          );
        }
        // 마지막 갱신 시간 기록
        setLastRefreshedAt(new Date());
      } 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);
    }
  };

  // 위젯 새로고침 핸들러
  const handleRefresh = async () => {
    setIsRefreshing(true);
    setSelectedObject(null);
    setMaterials([]);
    setShowInfoPanel(false);
    await loadLayout();
    setIsRefreshing(false);
    toast({
      title: "새로고침 완료",
      description: "데이터가 갱신되었습니다.",
    });
  };

  // 초기 로드
  useEffect(() => {
    loadLayout();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [layoutId]);

  // 10초 주기 자동 갱신 (중앙 관제 화면 자동 새로고침)
  useEffect(() => {
    const AUTO_REFRESH_INTERVAL = 10000; // 10초

    const silentRefresh = async () => {
      // 로딩 중이거나 새로고침 중이면 스킵
      if (isLoading || isRefreshing) return;

      try {
        // 레이아웃 데이터 조용히 갱신
        const response = await getLayoutById(layoutId);

        if (response.success && response.data) {
          const { layout, objects } = response.data;
          const dbConnectionId = layout.external_db_connection_id || layout.externalDbConnectionId;

          // hierarchy_config 파싱
          let hierarchyConfigData: any = null;
          if (layout.hierarchy_config) {
            hierarchyConfigData =
              typeof layout.hierarchy_config === "string"
                ? JSON.parse(layout.hierarchy_config)
                : layout.hierarchy_config;
            setHierarchyConfig(hierarchyConfigData);
          }

          // 객체 데이터 변환
          const loadedObjects: PlacedObject[] = objects.map((obj: any) => {
            const objectType = obj.object_type;
            return {
              id: obj.id,
              type: objectType,
              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: getObjectColor(objectType, obj.color),
              areaKey: obj.area_key,
              locaKey: obj.loca_key,
              locType: obj.loc_type,
              materialCount: obj.loc_type === "STP" ? undefined : obj.material_count,
              materialPreview:
                obj.loc_type === "STP" || !obj.material_preview_height
                  ? undefined
                  : { height: parseFloat(obj.material_preview_height) },
              parentId: obj.parent_id,
              displayOrder: obj.display_order,
              locked: obj.locked,
              visible: obj.visible !== false,
              hierarchyLevel: obj.hierarchy_level,
              parentKey: obj.parent_key,
              externalKey: obj.external_key,
            };
          });

          // 외부 DB 연결이 있고 자재 설정이 있으면, 각 Location의 실제 자재 개수 조회
          if (dbConnectionId && hierarchyConfigData?.material) {
            const locationObjects = loadedObjects.filter(
              (obj) =>
                (obj.type === "location-bed" || obj.type === "location-temp" || obj.type === "location-dest") &&
                obj.locaKey,
            );

            // 각 Location에 대해 자재 개수 조회 (병렬 처리)
            const materialCountPromises = locationObjects.map(async (obj) => {
              try {
                const matResponse = await getMaterials(dbConnectionId, {
                  tableName: hierarchyConfigData.material.tableName,
                  keyColumn: hierarchyConfigData.material.keyColumn,
                  locationKeyColumn: hierarchyConfigData.material.locationKeyColumn,
                  layerColumn: hierarchyConfigData.material.layerColumn,
                  locaKey: obj.locaKey!,
                });
                if (matResponse.success && matResponse.data) {
                  return { id: obj.id, count: matResponse.data.length };
                }
              } catch {
                // 자동 갱신 시에는 에러 로그 생략
              }
              return { id: obj.id, count: 0 };
            });

            const materialCounts = await Promise.all(materialCountPromises);

            // materialCount 업데이트
            const updatedObjects = loadedObjects.map((obj) => {
              const countData = materialCounts.find((m) => m.id === obj.id);
              if (countData && countData.count > 0) {
                return { ...obj, materialCount: countData.count };
              }
              return obj;
            });

            setPlacedObjects(updatedObjects);
          } else {
            setPlacedObjects(loadedObjects);
          }

          // 선택된 객체가 있으면 자재 목록도 갱신
          if (selectedObject && dbConnectionId && hierarchyConfigData?.material) {
            const currentObj = loadedObjects.find((o) => o.id === selectedObject.id);
            if (
              currentObj &&
              (currentObj.type === "location-bed" ||
                currentObj.type === "location-temp" ||
                currentObj.type === "location-dest") &&
              currentObj.locaKey
            ) {
              const matResponse = await getMaterials(dbConnectionId, {
                tableName: hierarchyConfigData.material.tableName,
                keyColumn: hierarchyConfigData.material.keyColumn,
                locationKeyColumn: hierarchyConfigData.material.locationKeyColumn,
                layerColumn: hierarchyConfigData.material.layerColumn,
                locaKey: currentObj.locaKey,
              });
              if (matResponse.success && matResponse.data) {
                const layerColumn = hierarchyConfigData.material.layerColumn || "LOLAYER";
                const sortedMaterials = matResponse.data.sort(
                  (a: any, b: any) => (b[layerColumn] || 0) - (a[layerColumn] || 0),
                );
                setMaterials(sortedMaterials);
              }
            }
          }

          // 마지막 갱신 시간 기록
          setLastRefreshedAt(new Date());
        }
      } catch {
        // 자동 갱신 실패 시 조용히 무시 (사용자 경험 방해 안 함)
      }
    };

    // 10초마다 자동 갱신
    const intervalId = setInterval(silentRefresh, AUTO_REFRESH_INTERVAL);

    // 컴포넌트 언마운트 시 인터벌 정리
    return () => clearInterval(intervalId);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [layoutId, isLoading, isRefreshing, selectedObject]);

  // Location의 자재 목록 로드
  const loadMaterialsForLocation = async (locaKey: string, externalDbConnectionId: number) => {
    if (!hierarchyConfig?.material) {
      console.warn("hierarchyConfig.material이 없습니다. 자재 로드를 건너뜁니다.");
      return;
    }

    try {
      setLoadingMaterials(true);
      setShowInfoPanel(true);

      const response = await getMaterials(externalDbConnectionId, {
        tableName: hierarchyConfig.material.tableName,
        keyColumn: hierarchyConfig.material.keyColumn,
        locationKeyColumn: hierarchyConfig.material.locationKeyColumn,
        layerColumn: hierarchyConfig.material.layerColumn,
        locaKey: locaKey,
      });
      if (response.success && response.data) {
        const layerColumn = hierarchyConfig.material.layerColumn || "LOLAYER";
        // 층 내림차순 정렬 (높은 층이 위로)
        const sortedMaterials = response.data.sort((a: any, b: any) => (b[layerColumn] || 0) - (a[layerColumn] || 0));
        setMaterials(sortedMaterials);
      } else {
        setMaterials([]);
      }
    } catch (error) {
      console.error("자재 로드 실패:", error);
      setMaterials([]);
    } finally {
      setLoadingMaterials(false);
    }
  };

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

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

    // Location을 클릭한 경우, 자재 정보 표시 (STP는 자재 미적재이므로 제외)
    if (
      obj &&
      (obj.type === "location-bed" || obj.type === "location-temp" || obj.type === "location-dest") &&
      obj.locaKey &&
      externalDbConnectionId
    ) {
      setShowInfoPanel(true);
      loadMaterialsForLocation(obj.locaKey, externalDbConnectionId);
    } else {
      setShowInfoPanel(true);
      setMaterials([]);
    }
  };

  // 타입별 개수 계산 (useMemo로 최적화)
  const typeCounts = useMemo(() => {
    const counts: Record<string, number> = {
      all: placedObjects.length,
      area: 0,
      "location-bed": 0,
      "location-stp": 0,
      "location-temp": 0,
      "location-dest": 0,
      "crane-mobile": 0,
      rack: 0,
    };

    placedObjects.forEach((obj) => {
      if (counts[obj.type] !== undefined) {
        counts[obj.type]++;
      }
    });

    return counts;
  }, [placedObjects]);

  // 필터링된 객체 목록 (useMemo로 최적화)
  const filteredObjects = useMemo(() => {
    return placedObjects.filter((obj) => {
      // 타입 필터
      if (filterType !== "all" && obj.type !== filterType) {
        return false;
      }

      // 검색 쿼리
      if (searchQuery) {
        const query = searchQuery.toLowerCase();
        return (
          obj.name.toLowerCase().includes(query) ||
          obj.areaKey?.toLowerCase().includes(query) ||
          obj.locaKey?.toLowerCase().includes(query)
        );
      }

      return true;
    });
  }, [placedObjects, filterType, searchQuery]);

  // 객체 타입별 기본 색상 (useMemo로 최적화)
  const getObjectColor = useMemo(() => {
    return (type: string, savedColor?: string): string => {
      // 저장된 색상이 있으면 우선 사용
      if (savedColor) return savedColor;
      // 없으면 타입별 기본 색상 사용
      return OBJECT_COLORS[type] || DEFAULT_COLOR;
    };
  }, []);

  // 3D 캔버스용 placements 변환 (useMemo로 최적화)
  const canvasPlacements = useMemo(() => {
    return placedObjects.map((obj) => ({
      id: obj.id,
      name: obj.name,
      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,
      material_count: obj.materialCount,
      material_preview_height: obj.materialPreview?.height,
      yard_layout_id: undefined,
      material_code: null,
      material_name: null,
      quantity: null,
      unit: null,
      data_source_config: undefined,
      data_binding: undefined,
      created_at: new Date().toISOString(),
      updated_at: new Date().toISOString(),
    }));
  }, [placedObjects]);

  if (isLoading) {
    return (
      <div className="flex h-full items-center justify-center">
        <Loader2 className="text-muted-foreground h-8 w-8 animate-spin" />
      </div>
    );
  }

  return (
    <div className="bg-background flex h-full flex-col">
      {/* 상단 헤더 */}
      <div className="flex items-center justify-between border-b p-4">
        <div>
          <h2 className="text-lg font-semibold">{layoutName || "디지털 트윈 야드"}</h2>
          <div className="flex items-center gap-3">
            <p className="text-muted-foreground text-sm">{isExternalMode ? "야드 관제 화면" : "읽기 전용 뷰"}</p>
            {lastRefreshedAt && (
              <span className="text-muted-foreground text-xs">
                마지막 갱신: {lastRefreshedAt.toLocaleTimeString("ko-KR")}
              </span>
            )}
          </div>
        </div>
        <div className="flex items-center gap-2">
          {/* 전체 화면 버튼 - 외부 업체 모드에서만 표시 */}
          {isExternalMode && (
            <Button
              variant="outline"
              size="sm"
              onClick={toggleFullscreen}
              title={isFullscreen ? "전체 화면 종료" : "전체 화면"}
            >
              {isFullscreen ? <Minimize className="mr-2 h-4 w-4" /> : <Maximize className="mr-2 h-4 w-4" />}
              {isFullscreen ? "종료" : "전체 화면"}
            </Button>
          )}
          <Button
            variant="outline"
            size="sm"
            onClick={handleRefresh}
            disabled={isRefreshing || isLoading}
            title="새로고침"
          >
            <RefreshCw className={`mr-2 h-4 w-4 ${isRefreshing ? "animate-spin" : ""}`} />
            {isRefreshing ? "갱신 중..." : "새로고침"}
          </Button>
        </div>
      </div>

      {/* 메인 영역 */}
      <div className="flex flex-1 overflow-hidden">
        {/* 좌측: 검색/필터 - 외부 모드에서는 숨김 */}
        {!isExternalMode && (
          <div className="flex h-full w-64 flex-shrink-0 flex-col border-r">
            <div className="space-y-4 p-4">
              {/* 검색 */}
              <div>
                <Label className="mb-2 block text-sm font-semibold">검색</Label>
                <div className="relative">
                  <Search className="text-muted-foreground absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2" />
                  <Input
                    value={searchQuery}
                    onChange={(e) => setSearchQuery(e.target.value)}
                    placeholder="이름, Area, Location 검색..."
                    className="h-10 pl-9 text-sm"
                  />
                  {searchQuery && (
                    <Button
                      variant="ghost"
                      size="sm"
                      className="absolute top-1/2 right-1 h-7 w-7 -translate-y-1/2 p-0"
                      onClick={() => setSearchQuery("")}
                    >
                      <X className="h-3 w-3" />
                    </Button>
                  )}
                </div>
              </div>

              {/* 타입 필터 */}
              <div>
                <Label className="mb-2 block text-sm font-semibold">타입 필터</Label>
                <Select value={filterType} onValueChange={setFilterType}>
                  <SelectTrigger className="h-10 text-sm">
                    <SelectValue />
                  </SelectTrigger>
                  <SelectContent>
                    <SelectItem value="all">전체 ({typeCounts.all})</SelectItem>
                    <SelectItem value="area">Area ({typeCounts.area})</SelectItem>
                    <SelectItem value="location-bed">베드(BED) ({typeCounts["location-bed"]})</SelectItem>
                    <SelectItem value="location-stp">정차포인트(STP) ({typeCounts["location-stp"]})</SelectItem>
                    <SelectItem value="location-temp">임시베드(TMP) ({typeCounts["location-temp"]})</SelectItem>
                    <SelectItem value="location-dest">지정착지(DES) ({typeCounts["location-dest"]})</SelectItem>
                    <SelectItem value="crane-mobile">크레인 ({typeCounts["crane-mobile"]})</SelectItem>
                    <SelectItem value="rack">랙 ({typeCounts.rack})</SelectItem>
                  </SelectContent>
                </Select>
              </div>

              {/* 필터 초기화 */}
              {(searchQuery || filterType !== "all") && (
                <Button
                  variant="outline"
                  size="sm"
                  className="h-9 w-full text-sm"
                  onClick={() => {
                    setSearchQuery("");
                    setFilterType("all");
                  }}
                >
                  필터 초기화
                </Button>
              )}
            </div>

            {/* 객체 목록 */}
            <div className="flex-1 overflow-y-auto border-t p-4">
              <Label className="mb-2 block text-sm font-semibold">객체 목록 ({filteredObjects.length})</Label>
              {filteredObjects.length === 0 ? (
                <div className="text-muted-foreground flex h-32 items-center justify-center text-center text-sm">
                  {searchQuery ? "검색 결과가 없습니다" : "객체가 없습니다"}
                </div>
              ) : (
                (() => {
                  // Area 객체가 있는 경우 계층 트리 아코디언 적용
                  const areaObjects = filteredObjects.filter((obj) => obj.type === "area");

                  // Area가 없으면 기존 평면 리스트 유지
                  if (areaObjects.length === 0) {
                    return (
                      <div className="space-y-2">
                        {filteredObjects.map((obj) => {
                          let typeLabel = obj.type;
                          if (obj.type === "location-bed") typeLabel = "베드(BED)";
                          else if (obj.type === "location-stp") typeLabel = "정차포인트(STP)";
                          else if (obj.type === "location-temp") typeLabel = "임시베드(TMP)";
                          else if (obj.type === "location-dest") typeLabel = "지정착지(DES)";
                          else if (obj.type === "crane-mobile") typeLabel = "크레인";
                          else if (obj.type === "area") typeLabel = "Area";
                          else if (obj.type === "rack") typeLabel = "랙";

                          return (
                            <div
                              key={obj.id}
                              onClick={() => handleObjectClick(obj.id)}
                              className={`bg-background hover:bg-accent cursor-pointer rounded-lg border p-3 transition-all ${
                                selectedObject?.id === obj.id ? "ring-primary bg-primary/5 ring-2" : "hover:shadow-sm"
                              }`}
                            >
                              <div className="flex items-start justify-between">
                                <div className="flex-1">
                                  <p className="text-sm font-medium">{obj.name}</p>
                                  <div className="text-muted-foreground mt-1 flex items-center gap-2 text-xs">
                                    <span
                                      className="inline-block h-2 w-2 rounded-full"
                                      style={{ backgroundColor: obj.color }}
                                    />
                                    <span>{typeLabel}</span>
                                  </div>
                                </div>
                              </div>
                              <div className="mt-2 space-y-1">
                                {obj.areaKey && (
                                  <p className="text-muted-foreground text-xs">
                                    Area: <span className="font-medium">{obj.areaKey}</span>
                                  </p>
                                )}
                                {obj.locaKey && (
                                  <p className="text-muted-foreground text-xs">
                                    Location: <span className="font-medium">{obj.locaKey}</span>
                                  </p>
                                )}
                                {obj.materialCount !== undefined && obj.materialCount > 0 && (
                                  <p className="text-xs text-amber-600">
                                    자재: <span className="font-semibold">{obj.materialCount}개</span>
                                  </p>
                                )}
                              </div>
                            </div>
                          );
                        })}
                      </div>
                    );
                  }

                  // Area가 있는 경우: Area → Location 계층 아코디언
                  return (
                    <Accordion type="multiple" className="w-full">
                      {areaObjects.map((areaObj) => {
                        const childLocations = filteredObjects.filter(
                          (obj) =>
                            obj.type !== "area" &&
                            obj.areaKey === areaObj.areaKey &&
                            (obj.parentId === areaObj.id || obj.externalKey === areaObj.externalKey),
                        );

                        return (
                          <AccordionItem key={areaObj.id} value={`area-${areaObj.id}`} className="border-b">
                            <AccordionTrigger className="px-2 py-3 hover:no-underline">
                              <div
                                className={`flex w-full items-center justify-between pr-2 ${
                                  selectedObject?.id === areaObj.id ? "text-primary font-semibold" : ""
                                }`}
                                onClick={(e) => {
                                  e.stopPropagation();
                                  handleObjectClick(areaObj.id);
                                }}
                              >
                                <div className="flex items-center gap-2">
                                  <Grid3x3 className="h-4 w-4" />
                                  <span className="text-sm font-medium">{areaObj.name}</span>
                                </div>
                                <div className="flex items-center gap-2">
                                  <span className="text-muted-foreground text-xs">({childLocations.length})</span>
                                  <span
                                    className="inline-block h-2 w-2 rounded-full"
                                    style={{ backgroundColor: areaObj.color }}
                                  />
                                </div>
                              </div>
                            </AccordionTrigger>
                            <AccordionContent className="px-2 pb-3">
                              {childLocations.length === 0 ? (
                                <p className="text-muted-foreground py-2 text-center text-xs">Location이 없습니다</p>
                              ) : (
                                <div className="space-y-2">
                                  {childLocations.map((locationObj) => (
                                    <div
                                      key={locationObj.id}
                                      onClick={() => handleObjectClick(locationObj.id)}
                                      className={`cursor-pointer rounded-lg border p-2 transition-all ${
                                        selectedObject?.id === locationObj.id
                                          ? "border-primary bg-primary/10"
                                          : "hover:border-primary/50"
                                      }`}
                                    >
                                      <div className="flex items-center justify-between">
                                        <div className="flex items-center gap-2">
                                          {locationObj.type === "location-stp" ? (
                                            <ParkingCircle className="h-3 w-3" />
                                          ) : (
                                            <Package className="h-3 w-3" />
                                          )}
                                          <span className="text-xs font-medium">{locationObj.name}</span>
                                        </div>
                                        <span
                                          className="inline-block h-2.5 w-2.5 rounded-full"
                                          style={{ backgroundColor: locationObj.color }}
                                        />
                                      </div>
                                      <p className="text-muted-foreground mt-1 text-[10px]">
                                        위치: ({locationObj.position.x.toFixed(1)}, {locationObj.position.z.toFixed(1)})
                                      </p>
                                      {locationObj.locaKey && (
                                        <p className="text-muted-foreground mt-0.5 text-[10px]">
                                          Location: <span className="font-medium">{locationObj.locaKey}</span>
                                        </p>
                                      )}
                                      {locationObj.materialCount !== undefined && locationObj.materialCount > 0 && (
                                        <p className="mt-0.5 text-[10px] text-amber-600">
                                          자재: <span className="font-semibold">{locationObj.materialCount}개</span>
                                        </p>
                                      )}
                                    </div>
                                  ))}
                                </div>
                              )}
                            </AccordionContent>
                          </AccordionItem>
                        );
                      })}
                    </Accordion>
                  );
                })()
              )}
            </div>
          </div>
        )}

        {/* 중앙 + 우측 컨테이너 (전체화면 시 함께 표시) */}
        <div
          ref={canvasContainerRef}
          className={`relative flex flex-1 overflow-hidden ${isFullscreen ? "bg-background" : ""}`}
        >
          {/* 중앙: 3D 캔버스 */}
          <div className="relative min-w-0 flex-1">
            {!isLoading && (
              <Yard3DCanvas
                placements={canvasPlacements}
                selectedPlacementId={selectedObject?.id || null}
                onPlacementClick={(placement) => handleObjectClick(placement?.id || null)}
                focusOnPlacementId={null}
                onCollisionDetected={() => {}}
              />
            )}
          </div>

          {/* 우측: 정보 패널 */}
          <div className="h-full w-[480px] min-w-[480px] flex-shrink-0 overflow-y-auto border-l">
            {selectedObject ? (
              <div className="p-4">
                <div className="mb-4">
                  <h3 className="text-lg font-semibold">상세 정보</h3>
                  <p className="text-muted-foreground text-xs">{selectedObject.name}</p>
                </div>

                {/* 기본 정보 */}
                <div className="bg-muted space-y-3 rounded-lg p-3">
                  <div>
                    <Label className="text-muted-foreground text-xs">타입</Label>
                    <p className="text-sm font-medium">{selectedObject.type}</p>
                  </div>
                  {selectedObject.areaKey && (
                    <div>
                      <Label className="text-muted-foreground text-xs">Area Key</Label>
                      <p className="text-sm font-medium">{selectedObject.areaKey}</p>
                    </div>
                  )}
                  {selectedObject.locaKey && (
                    <div>
                      <Label className="text-muted-foreground text-xs">Location Key</Label>
                      <p className="text-sm font-medium">{selectedObject.locaKey}</p>
                    </div>
                  )}
                  {selectedObject.materialCount !== undefined && selectedObject.materialCount > 0 && (
                    <div>
                      <Label className="text-muted-foreground text-xs">자재 개수</Label>
                      <p className="text-sm font-medium">{selectedObject.materialCount}개</p>
                    </div>
                  )}
                </div>

                {/* 자재 목록 (Location인 경우) - 테이블 형태 */}
                {(selectedObject.type === "location-bed" ||
                  selectedObject.type === "location-stp" ||
                  selectedObject.type === "location-temp" ||
                  selectedObject.type === "location-dest") && (
                  <div className="mt-4">
                    {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-center text-sm">
                        {externalDbConnectionId ? "자재가 없습니다" : "외부 DB 연결이 설정되지 않았습니다"}
                      </div>
                    ) : (
                      <div className="space-y-2">
                        <Label className="mb-2 block text-sm font-semibold">자재 목록 ({materials.length}개)</Label>
                        {/* 테이블 형태로 전체 조회 */}
                        <div className="h-[580px] overflow-auto rounded-lg border">
                          <table className="w-full text-sm">
                            <thead className="bg-muted sticky top-0">
                              <tr>
                                <th className="border-b px-3 py-3 text-left font-semibold whitespace-nowrap">층</th>
                                {(hierarchyConfig?.material?.displayColumns || []).map((colConfig: any) => (
                                  <th key={colConfig.column} className="border-b px-3 py-3 text-left font-semibold">
                                    {colConfig.label}
                                  </th>
                                ))}
                              </tr>
                            </thead>
                            <tbody>
                              {materials.map((material, index) => {
                                const layerColumn = hierarchyConfig?.material?.layerColumn || "LOLAYER";
                                const displayColumns = hierarchyConfig?.material?.displayColumns || [];
                                return (
                                  <tr
                                    key={`${material.STKKEY}-${index}`}
                                    className="hover:bg-accent border-b transition-colors last:border-0"
                                  >
                                    <td className="px-3 py-3 font-medium whitespace-nowrap">
                                      {material[layerColumn]}단
                                    </td>
                                    {displayColumns.map((colConfig: any) => (
                                      <td key={colConfig.column} className="px-3 py-3">
                                        {material[colConfig.column] || "-"}
                                      </td>
                                    ))}
                                  </tr>
                                );
                              })}
                            </tbody>
                          </table>
                        </div>
                      </div>
                    )}
                  </div>
                )}
              </div>
            ) : (
              <div className="flex h-full items-center justify-center p-4">
                <p className="text-muted-foreground text-sm">객체를 선택하세요</p>
              </div>
            )}
          </div>

          {/* 풀스크린 모드일 때 종료 버튼 */}
          {isFullscreen && (
            <Button
              variant="outline"
              size="sm"
              onClick={toggleFullscreen}
              className="bg-background/80 absolute top-4 right-4 z-50 backdrop-blur-sm"
            >
              <Minimize className="mr-2 h-4 w-4" />
              종료
            </Button>
          )}
        </div>
      </div>
    </div>
  );
}
