"use client";

import { useCallback, useRef, useState, useEffect, useMemo } from "react";
import { useDrop } from "react-dnd";
import { cn } from "@/lib/utils";
import {
  PopLayoutData,
  PopComponentDefinition,
  PopComponentType,
  PopGridPosition,
  GridMode,
  GapPreset,
  GAP_PRESETS,
  GRID_BREAKPOINTS,
  DEFAULT_COMPONENT_GRID_SIZE,
  PopModalDefinition,
  ModalSizePreset,
  MODAL_SIZE_PRESETS,
  resolveModalWidth,
  BLOCK_SIZE,
  BLOCK_GAP,
  BLOCK_PADDING,
  getBlockColumns,
} from "./types/pop-layout";
import { ZoomIn, ZoomOut, Maximize2, Smartphone, Tablet, Lock, RotateCcw, EyeOff, Monitor, ChevronDown, ChevronUp } from "lucide-react";
import { useDrag } from "react-dnd";
import { Button } from "@/components/ui/button";
import { 
  Select, 
  SelectContent, 
  SelectItem, 
  SelectTrigger, 
  SelectValue 
} from "@/components/ui/select";
import { toast } from "sonner";
import PopRenderer from "./renderers/PopRenderer";
import { findNextEmptyPosition, isOverlapping, getAllEffectivePositions } from "./utils/gridUtils";
import { DND_ITEM_TYPES } from "./constants";

/**
 * V6: 캔버스 내 상대 좌표 → 블록 그리드 좌표 변환
 * 블록 크기가 고정(BLOCK_SIZE)이므로 1fr 계산 불필요
 */
function calcGridPosition(
  relX: number,
  relY: number,
  canvasWidth: number,
  columns: number,
  rowHeight: number,
  gap: number,
  padding: number
): { col: number; row: number } {
  const x = relX - padding;
  const y = relY - padding;
  
  const cellStride = BLOCK_SIZE + gap;
  
  const col = Math.max(1, Math.min(columns, Math.floor(x / cellStride) + 1));
  const row = Math.max(1, Math.floor(y / cellStride) + 1);
  
  return { col, row };
}

// 드래그 아이템 타입 정의
interface DragItemComponent {
  type: typeof DND_ITEM_TYPES.COMPONENT;
  componentType: PopComponentType;
}

interface DragItemMoveComponent {
  componentId: string;
  originalPosition: PopGridPosition;
}

// ========================================
// V6: 프리셋 해상도 (블록 칸 수 동적 계산)
// ========================================
const VIEWPORT_PRESETS = [
  { id: "mobile_portrait", label: "모바일 세로", shortLabel: `모바일↕ (${getBlockColumns(375)}칸)`, width: 375, icon: Smartphone },
  { id: "mobile_landscape", label: "모바일 가로", shortLabel: `모바일↔ (${getBlockColumns(600)}칸)`, width: 600, icon: Smartphone },
  { id: "tablet_portrait", label: "태블릿 세로", shortLabel: `태블릿↕ (${getBlockColumns(820)}칸)`, width: 820, icon: Tablet },
  { id: "tablet_landscape", label: "태블릿 가로", shortLabel: `태블릿↔ (${getBlockColumns(1024)}칸)`, width: 1024, icon: Tablet },
] as const;

type ViewportPreset = GridMode;

// 기본 프리셋 (태블릿 가로)
const DEFAULT_PRESET: ViewportPreset = "tablet_landscape";

// 캔버스 세로 자동 확장 설정
const MIN_CANVAS_HEIGHT = 600; // 최소 캔버스 높이 (px)
const CANVAS_EXTRA_ROWS = 3;   // 여유 행 수

// ========================================
// Props
// ========================================
interface PopCanvasProps {
  layout: PopLayoutData;
  selectedComponentId: string | null;
  currentMode: GridMode;
  onModeChange: (mode: GridMode) => void;
  onSelectComponent: (id: string | null) => void;
  onDropComponent: (type: PopComponentType, position: PopGridPosition) => void;
  onUpdateComponent: (componentId: string, updates: Partial<PopComponentDefinition>) => void;
  onDeleteComponent: (componentId: string) => void;
  onMoveComponent?: (componentId: string, newPosition: PopGridPosition) => void;
  onResizeComponent?: (componentId: string, newPosition: PopGridPosition) => void;
  onResizeEnd?: (componentId: string) => void;
  onHideComponent?: (componentId: string) => void;
  onUnhideComponent?: (componentId: string) => void;
  onLockLayout?: () => void;
  onResetOverride?: (mode: GridMode) => void;
  onChangeGapPreset?: (preset: GapPreset) => void;
  /** 컴포넌트가 자신의 rowSpan/colSpan 변경을 요청 (CardList 확장 등) */
  onRequestResize?: (componentId: string, newRowSpan: number, newColSpan?: number) => void;
  /** 대시보드 페이지 미리보기 인덱스 (-1이면 기본 모드) */
  previewPageIndex?: number;
  /** 현재 활성 캔버스 ID ("main" 또는 모달 ID) */
  activeCanvasId?: string;
  /** 캔버스 전환 콜백 */
  onActiveCanvasChange?: (canvasId: string) => void;
  /** 모달 정의 업데이트 콜백 */
  onUpdateModal?: (modalId: string, updates: Partial<PopModalDefinition>) => void;
}

// ========================================
// PopCanvas: 그리드 캔버스
// ========================================

export default function PopCanvas({
  layout,
  selectedComponentId,
  currentMode,
  onModeChange,
  onSelectComponent,
  onDropComponent,
  onUpdateComponent,
  onDeleteComponent,
  onMoveComponent,
  onResizeComponent,
  onResizeEnd,
  onHideComponent,
  onUnhideComponent,
  onLockLayout,
  onResetOverride,
  onChangeGapPreset,
  onRequestResize,
  previewPageIndex,
  activeCanvasId = "main",
  onActiveCanvasChange,
  onUpdateModal,
}: PopCanvasProps) {
  // 모달 탭 데이터
  const modalTabs = useMemo(() => {
    const tabs: { id: string; label: string }[] = [{ id: "main", label: "메인화면" }];
    if (layout.modals?.length) {
      for (const modal of layout.modals) {
        const numbering = modal.id.replace("modal-", "");
        tabs.push({ id: modal.id, label: `모달화면 ${numbering}` });
      }
    }
    return tabs;
  }, [layout.modals]);

  // activeCanvasId에 따라 렌더링할 layout 분기
  const activeLayout = useMemo((): PopLayoutData => {
    if (activeCanvasId === "main") return layout;
    const modal = layout.modals?.find(m => m.id === activeCanvasId);
    if (!modal) return layout; // fallback
    return {
      ...layout,
      gridConfig: modal.gridConfig,
      components: modal.components,
      overrides: modal.overrides,
    };
  }, [layout, activeCanvasId]);

  // 현재 활성 모달 정의 (모달 캔버스일 때만)
  const activeModal = useMemo(() => {
    if (activeCanvasId === "main") return null;
    return layout.modals?.find(m => m.id === activeCanvasId) || null;
  }, [layout.modals, activeCanvasId]);

  // 줌 상태
  const [canvasScale, setCanvasScale] = useState(0.8);
  
  // 커스텀 뷰포트 너비
  const [customWidth, setCustomWidth] = useState(1024);
  
  // 그리드 가이드 표시 여부
  const [showGridGuide, setShowGridGuide] = useState(true);
  
  // 패닝 상태
  const [isPanning, setIsPanning] = useState(false);
  const [panStart, setPanStart] = useState({ x: 0, y: 0 });
  const [isSpacePressed, setIsSpacePressed] = useState(false);
  const containerRef = useRef<HTMLDivElement>(null);
  const canvasRef = useRef<HTMLDivElement>(null);

  // V6: 뷰포트에서 동적 블록 칸 수 계산
  const currentPreset = VIEWPORT_PRESETS.find((p) => p.id === currentMode)!;
  const dynamicColumns = getBlockColumns(customWidth);
  const breakpoint = {
    ...GRID_BREAKPOINTS[currentMode],
    columns: dynamicColumns,
    rowHeight: BLOCK_SIZE,
    gap: BLOCK_GAP,
    padding: BLOCK_PADDING,
    label: `${dynamicColumns}칸 블록`,
  };
  
  // V6: 블록 간격 고정 (프리셋 무관)
  const currentGapPreset = layout.settings.gapPreset || "medium";
  const adjustedGap = BLOCK_GAP;
  const adjustedPadding = BLOCK_PADDING;
  
  // 숨김 컴포넌트 ID 목록 (activeLayout 기반)
  const hiddenComponentIds = activeLayout.overrides?.[currentMode]?.hidden || [];
  
  // 동적 캔버스 높이 계산 (컴포넌트 배치 기반)
  const dynamicCanvasHeight = useMemo(() => {
    const visibleComps = Object.values(activeLayout.components).filter(
      comp => !hiddenComponentIds.includes(comp.id)
    );
    
    if (visibleComps.length === 0) return MIN_CANVAS_HEIGHT;
    
    // 최대 row + rowSpan 찾기
    const maxRowEnd = visibleComps.reduce((max, comp) => {
      const overridePos = layout.overrides?.[currentMode]?.positions?.[comp.id];
      const pos = overridePos ? { ...comp.position, ...overridePos } : comp.position;
      const rowEnd = pos.row + pos.rowSpan;
      return Math.max(max, rowEnd);
    }, 1);
    
    // 높이 계산: (행 수 + 여유) * (행높이 + gap) + padding
    const totalRows = maxRowEnd + CANVAS_EXTRA_ROWS;
    const height = totalRows * (breakpoint.rowHeight + adjustedGap) + adjustedPadding * 2;
    
    return Math.max(MIN_CANVAS_HEIGHT, height);
  }, [activeLayout.components, activeLayout.overrides, currentMode, hiddenComponentIds, breakpoint.rowHeight, adjustedGap, adjustedPadding]);
  
  // 그리드 라벨 계산 (동적 행 수)
  const gridLabels = useMemo(() => {
    const columnLabels = Array.from({ length: breakpoint.columns }, (_, i) => i + 1);
    
    // 동적 행 수 계산
    const rowCount = Math.ceil(dynamicCanvasHeight / (breakpoint.rowHeight + adjustedGap));
    const rowLabels = Array.from({ length: rowCount }, (_, i) => i + 1);
    
    return { columnLabels, rowLabels };
  }, [breakpoint.columns, breakpoint.rowHeight, dynamicCanvasHeight, adjustedGap]);

  // 줌 컨트롤
  const handleZoomIn = () => setCanvasScale((prev) => Math.min(1.5, prev + 0.1));
  const handleZoomOut = () => setCanvasScale((prev) => Math.max(0.3, prev - 0.1));
  const handleZoomFit = () => setCanvasScale(1.0);

  // 모드 변경
  const handleViewportChange = (mode: GridMode) => {
    onModeChange(mode);
    const presetData = VIEWPORT_PRESETS.find((p) => p.id === mode)!;
    setCustomWidth(presetData.width);
    // customHeight는 dynamicCanvasHeight로 자동 계산됨
  };

  // 패닝
  const handlePanStart = (e: React.MouseEvent) => {
    const isMiddleButton = e.button === 1;
    if (isMiddleButton || isSpacePressed) {
      setIsPanning(true);
      setPanStart({ x: e.clientX, y: e.clientY });
      e.preventDefault();
    }
  };

  const handlePanMove = (e: React.MouseEvent) => {
    if (!isPanning || !containerRef.current) return;
    const deltaX = e.clientX - panStart.x;
    const deltaY = e.clientY - panStart.y;
    containerRef.current.scrollLeft -= deltaX;
    containerRef.current.scrollTop -= deltaY;
    setPanStart({ x: e.clientX, y: e.clientY });
  };

  const handlePanEnd = () => setIsPanning(false);

  // Ctrl + 휠로 줌 조정
  const handleWheel = (e: React.WheelEvent) => {
    if (e.ctrlKey || e.metaKey) {
      e.preventDefault();
      const delta = e.deltaY > 0 ? -0.1 : 0.1;
      setCanvasScale((prev) => Math.max(0.3, Math.min(1.5, prev + delta)));
    }
  };

  // Space 키 감지
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.code === "Space" && !isSpacePressed) setIsSpacePressed(true);
    };
    const handleKeyUp = (e: KeyboardEvent) => {
      if (e.code === "Space") setIsSpacePressed(false);
    };
    window.addEventListener("keydown", handleKeyDown);
    window.addEventListener("keyup", handleKeyUp);
    return () => {
      window.removeEventListener("keydown", handleKeyDown);
      window.removeEventListener("keyup", handleKeyUp);
    };
  }, [isSpacePressed]);

  // 통합 드롭 핸들러 (팔레트에서 추가 + 컴포넌트 이동)
  const [{ isOver, canDrop }, drop] = useDrop(
    () => ({
      accept: [DND_ITEM_TYPES.COMPONENT, DND_ITEM_TYPES.MOVE_COMPONENT],
      drop: (item: DragItemComponent | DragItemMoveComponent, monitor) => {
        if (!canvasRef.current) return;
        
        const canvasRect = canvasRef.current.getBoundingClientRect();
        const itemType = monitor.getItemType();
        
        // 팔레트에서 새 컴포넌트 추가 - 마우스 위치 기준
        if (itemType === DND_ITEM_TYPES.COMPONENT) {
          const offset = monitor.getClientOffset();
          if (!offset) return;
          
          // 캔버스 내 상대 좌표 (스케일 보정)
          // canvasRect는 scale 적용된 크기이므로, 상대 좌표를 scale로 나눠야 실제 좌표
          const relX = (offset.x - canvasRect.left) / canvasScale;
          const relY = (offset.y - canvasRect.top) / canvasScale;
          
          // 그리드 좌표 계산
          const gridPos = calcGridPosition(
            relX,
            relY,
            customWidth,
            breakpoint.columns,
            breakpoint.rowHeight,
            adjustedGap,
            adjustedPadding
          );
          
          const dragItem = item as DragItemComponent;
          const defaultSize = DEFAULT_COMPONENT_GRID_SIZE[dragItem.componentType];
          
          const candidatePosition: PopGridPosition = {
            col: gridPos.col,
            row: gridPos.row,
            colSpan: defaultSize.colSpan,
            rowSpan: defaultSize.rowSpan,
          };
          
          // 현재 모드에서의 유효 위치들로 중첩 검사
          const effectivePositions = getAllEffectivePositions(activeLayout, currentMode);
          const existingPositions = Array.from(effectivePositions.values());
          
          const hasOverlap = existingPositions.some(pos => 
            isOverlapping(candidatePosition, pos)
          );
          
          let finalPosition: PopGridPosition;
          
          if (hasOverlap) {
            finalPosition = findNextEmptyPosition(
              existingPositions,
              defaultSize.colSpan,
              defaultSize.rowSpan,
              breakpoint.columns
            );
            toast.info("겹치는 위치입니다. 빈 위치로 자동 배치됩니다.");
          } else {
            finalPosition = candidatePosition;
          }
          
          onDropComponent(dragItem.componentType, finalPosition);
        }
        
        // 기존 컴포넌트 이동 - 마우스 위치 기준
        if (itemType === DND_ITEM_TYPES.MOVE_COMPONENT) {
          const offset = monitor.getClientOffset();
          if (!offset) return;
          
          // 캔버스 내 상대 좌표 (스케일 보정)
          const relX = (offset.x - canvasRect.left) / canvasScale;
          const relY = (offset.y - canvasRect.top) / canvasScale;
          
          const gridPos = calcGridPosition(
            relX,
            relY,
            customWidth,
            breakpoint.columns,
            breakpoint.rowHeight,
            adjustedGap,
            adjustedPadding
          );
          
          const dragItem = item as DragItemMoveComponent & { fromHidden?: boolean };
          
          // 현재 모드에서의 유효 위치들 가져오기
          const effectivePositions = getAllEffectivePositions(activeLayout, currentMode);
          
          // 이동 중인 컴포넌트의 현재 유효 위치에서 colSpan/rowSpan 가져오기
          // 숨김 컴포넌트는 effectivePositions에 없으므로 원본 사용
          const currentEffectivePos = effectivePositions.get(dragItem.componentId);
          const componentData = activeLayout.components[dragItem.componentId];
          
          if (!currentEffectivePos && !componentData) return;
          
          const sourcePosition = currentEffectivePos || componentData.position;
          
          // colSpan이 현재 모드의 columns를 초과하면 제한
          const adjustedColSpan = Math.min(sourcePosition.colSpan, breakpoint.columns);
          
          // 드롭 위치 + 크기가 범위를 초과하면 드롭 위치를 자동 조정
          let adjustedCol = gridPos.col;
          if (adjustedCol + adjustedColSpan - 1 > breakpoint.columns) {
            adjustedCol = Math.max(1, breakpoint.columns - adjustedColSpan + 1);
          }
          
          const newPosition: PopGridPosition = {
            col: adjustedCol,
            row: gridPos.row,
            colSpan: adjustedColSpan,
            rowSpan: sourcePosition.rowSpan,
          };
          
          // 자기 자신 제외한 다른 컴포넌트들의 유효 위치와 겹침 체크
          const hasOverlap = Array.from(effectivePositions.entries()).some(([id, pos]) => {
            if (id === dragItem.componentId) return false; // 자기 자신 제외
            return isOverlapping(newPosition, pos);
          });
          
          if (hasOverlap) {
            toast.error("이 위치로 이동할 수 없습니다 (다른 컴포넌트와 겹침)");
            return;
          }
          
          // 이동 처리 (숨김 컴포넌트의 경우 handleMoveComponent에서 숨김 해제도 함께 처리됨)
          onMoveComponent?.(dragItem.componentId, newPosition);
          
          // 숨김 패널에서 드래그한 경우 안내 메시지
          if (dragItem.fromHidden) {
            toast.info("컴포넌트가 다시 표시됩니다");
          }
        }
      },
      collect: (monitor) => ({
        isOver: monitor.isOver(),
        canDrop: monitor.canDrop(),
      }),
    }),
    [onDropComponent, onMoveComponent, onUnhideComponent, breakpoint, layout, activeLayout, currentMode, canvasScale, customWidth, adjustedGap, adjustedPadding]
  );

  drop(canvasRef);

  // 빈 상태 체크 (activeLayout 기반)
  const isEmpty = Object.keys(activeLayout.components).length === 0;
  
  // 숨김 처리된 컴포넌트 객체 목록
  const hiddenComponents = useMemo(() => {
    return hiddenComponentIds
      .map(id => activeLayout.components[id])
      .filter(Boolean);
  }, [hiddenComponentIds, activeLayout.components]);
  
  // 표시되는 컴포넌트 목록 (숨김 제외)
  const visibleComponents = useMemo(() => {
    return Object.values(activeLayout.components).filter(
      comp => !hiddenComponentIds.includes(comp.id)
    );
  }, [activeLayout.components, hiddenComponentIds]);
  
  const hasGridComponents = Object.keys(activeLayout.components).length > 0;
  const showHiddenPanel = currentMode !== "tablet_landscape" && (hiddenComponents.length > 0 || hasGridComponents);

  return (
    <div className="flex h-full flex-col bg-muted">
      {/* 상단 컨트롤 */}
      <div className="flex items-center gap-2 border-b bg-background px-4 py-2">
        {/* 모드 프리셋 버튼 */}
        <div className="flex gap-1">
          {VIEWPORT_PRESETS.map((preset) => {
            const Icon = preset.icon;
            const isActive = currentMode === preset.id;
            const isDefault = preset.id === DEFAULT_PRESET;
            
            return (
              <Button
                key={preset.id}
                variant={isActive ? "default" : "outline"}
                size="sm"
                onClick={() => handleViewportChange(preset.id as GridMode)}
                className={cn(
                  "h-8 gap-1 text-xs",
                  isActive && "shadow-sm"
                )}
              >
                <Icon className="h-3 w-3" />
                {preset.shortLabel}
                {isDefault && " (기본)"}
              </Button>
            );
          })}
        </div>

        <div className="h-4 w-px bg-border" />

        {/* 고정/되돌리기 버튼 (기본 모드 아닐 때만 표시) */}
        {currentMode !== DEFAULT_PRESET && (
          <>
            <Button
              variant="outline"
              size="sm"
              onClick={onLockLayout}
              className="h-8 gap-1 text-xs"
            >
              <Lock className="h-3 w-3" />
              고정
            </Button>
            
            {layout.overrides?.[currentMode] && (
              <Button
                variant="ghost"
                size="sm"
                onClick={() => onResetOverride?.(currentMode)}
                className="h-8 gap-1 text-xs"
              >
                <RotateCcw className="h-3 w-3" />
                자동으로 되돌리기
              </Button>
            )}
          </>
        )}

        <div className="h-4 w-px bg-border" />

        {/* 해상도 표시 */}
        <div className="text-xs text-muted-foreground">
          {customWidth} × {Math.round(dynamicCanvasHeight)}
        </div>
        
        <div className="h-4 w-px bg-border" />
        
        {/* Gap 프리셋 선택 */}
        <div className="flex items-center gap-2">
          <span className="text-xs text-muted-foreground">간격:</span>
          <Select
            value={currentGapPreset}
            onValueChange={(value) => onChangeGapPreset?.(value as GapPreset)}
          >
            <SelectTrigger className="h-8 w-20 text-xs">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              {(Object.keys(GAP_PRESETS) as GapPreset[]).map((preset) => (
                <SelectItem key={preset} value={preset} className="text-xs">
                  {GAP_PRESETS[preset].label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>

        <div className="flex-1" />

        {/* 줌 컨트롤 */}
        <div className="flex items-center gap-1">
          <span className="text-xs text-muted-foreground">
            {Math.round(canvasScale * 100)}%
          </span>
          <Button
            variant="ghost"
            size="icon"
            onClick={handleZoomOut}
            disabled={canvasScale <= 0.3}
            className="h-7 w-7"
          >
            <ZoomOut className="h-3 w-3" />
          </Button>
          <Button
            variant="ghost"
            size="icon"
            onClick={handleZoomFit}
            className="h-7 w-7"
          >
            <Maximize2 className="h-3 w-3" />
          </Button>
          <Button
            variant="ghost"
            size="icon"
            onClick={handleZoomIn}
            disabled={canvasScale >= 1.5}
            className="h-7 w-7"
          >
            <ZoomIn className="h-3 w-3" />
          </Button>
        </div>
        
        <div className="h-4 w-px bg-border" />
        
        {/* 그리드 가이드 토글 */}
        <Button
          variant={showGridGuide ? "default" : "outline"}
          size="sm"
          onClick={() => setShowGridGuide(!showGridGuide)}
          className="h-8 text-xs"
        >
          그리드 {showGridGuide ? "ON" : "OFF"}
        </Button>
      </div>

      {/* 모달 탭 바 (모달이 1개 이상 있을 때만 표시) */}
      {modalTabs.length > 1 && (
        <div className="flex gap-1 border-b bg-muted/30 px-4 py-1">
          {modalTabs.map(tab => (
            <Button
              key={tab.id}
              variant={activeCanvasId === tab.id ? "default" : "ghost"}
              size="sm"
              onClick={() => onActiveCanvasChange?.(tab.id)}
              className="h-7 text-xs"
            >
              {tab.label}
            </Button>
          ))}
        </div>
      )}

      {/* 모달 사이즈 설정 패널 (모달 캔버스 활성 시) */}
      {activeModal && (
        <ModalSizeSettingsPanel
          modal={activeModal}
          currentMode={currentMode}
          onUpdate={(updates) => onUpdateModal?.(activeModal.id, updates)}
        />
      )}

      {/* 캔버스 영역 */}
      <div
        ref={containerRef}
        className={cn(
          "canvas-scroll-area relative flex-1 overflow-auto bg-muted",
          isSpacePressed && "cursor-grab",
          isPanning && "cursor-grabbing"
        )}
        onMouseDown={handlePanStart}
        onMouseMove={handlePanMove}
        onMouseUp={handlePanEnd}
        onMouseLeave={handlePanEnd}
        onWheel={handleWheel}
      >
        <div
          className="relative mx-auto my-8 origin-top overflow-visible flex gap-4"
          style={{
            width: showHiddenPanel 
              ? `${customWidth + 32 + 220}px`  // 오른쪽 패널 공간 추가
              : `${customWidth + 32}px`,
            minHeight: `${dynamicCanvasHeight + 32}px`,
            transform: `scale(${canvasScale})`,
          }}
        >
          {/* 그리드 + 라벨 영역 */}
          <div className="relative">
            {/* 그리드 라벨 영역 */}
            {showGridGuide && (
              <>
                {/* 열 라벨 (상단) */}
                <div 
                  className="flex absolute top-0 left-8"
                  style={{
                    gap: `${adjustedGap}px`,
                    paddingLeft: `${adjustedPadding}px`,
                  }}
                >
                  {gridLabels.columnLabels.map((num) => (
                    <div
                      key={`col-${num}`}
                      className="flex items-center justify-center text-xs font-semibold text-primary"
                      style={{
                        width: `calc((${customWidth}px - ${adjustedPadding * 2}px - ${adjustedGap * (breakpoint.columns - 1)}px) / ${breakpoint.columns})`,
                        height: "24px",
                      }}
                    >
                      {num}
                    </div>
                  ))}
                </div>
                
                {/* 행 라벨 (좌측) */}
                <div 
                  className="flex flex-col absolute top-8 left-0"
                  style={{
                    gap: `${adjustedGap}px`,
                    paddingTop: `${adjustedPadding}px`,
                  }}
                >
                  {gridLabels.rowLabels.map((num) => (
                    <div
                      key={`row-${num}`}
                      className="flex items-center justify-center text-xs font-semibold text-primary"
                      style={{
                        width: "24px",
                        height: `${breakpoint.rowHeight}px`,
                      }}
                    >
                      {num}
                    </div>
                  ))}
                </div>
              </>
            )}
            
            {/* 디바이스 스크린 */}
            <div
              ref={canvasRef}
              className={cn(
                "relative rounded-lg border-2 bg-background shadow-xl overflow-visible",
                canDrop && isOver && "ring-4 ring-primary/20"
              )}
              style={{
                width: `${customWidth}px`,
                minHeight: `${dynamicCanvasHeight}px`,
                marginLeft: "32px",
                marginTop: "32px",
              }}
            >
              {isEmpty ? (
                // 빈 상태
                <div className="flex h-full items-center justify-center p-8">
                  <div className="text-center">
                    <div className="mb-2 text-sm font-medium text-muted-foreground">
                      컴포넌트를 드래그하여 배치하세요
                    </div>
                    <div className="text-xs text-muted-foreground/70">
                      {breakpoint.label} - {breakpoint.columns}칸 그리드
                    </div>
                  </div>
                </div>
              ) : (
                // 그리드 렌더러
                <PopRenderer
                  layout={activeLayout}
                  viewportWidth={customWidth}
                  currentMode={currentMode}
                  isDesignMode={true}
                  showGridGuide={showGridGuide}
                  selectedComponentId={selectedComponentId}
                  onComponentClick={onSelectComponent}
                  onBackgroundClick={() => onSelectComponent(null)}
                  onComponentMove={onMoveComponent}
                  onComponentResize={onResizeComponent}
                  onComponentResizeEnd={onResizeEnd}
                  onRequestResize={onRequestResize}
                  overrideGap={adjustedGap}
                  overridePadding={adjustedPadding}
                  previewPageIndex={previewPageIndex}
                />
              )}
            </div>
          </div>
          
          {/* 오른쪽 패널 영역 (초과 컴포넌트 + 숨김 컴포넌트) */}
          {showHiddenPanel && (
            <div
              className="flex flex-col gap-3"
              style={{ marginTop: "32px" }}
            >
              {/* 숨김 컴포넌트 패널 */}
              {showHiddenPanel && (
                <HiddenPanel
                  components={hiddenComponents}
                  selectedComponentId={selectedComponentId}
                  onSelectComponent={onSelectComponent}
                  onHideComponent={onHideComponent}
                />
              )}
            </div>
          )}
        </div>
      </div>

      {/* 하단 정보 */}
      <div className="flex items-center justify-between border-t bg-background px-4 py-2">
        <div className="text-xs text-muted-foreground">
          V6 블록 그리드 - {dynamicColumns}칸 (블록: {BLOCK_SIZE}px, 간격: {BLOCK_GAP}px)
        </div>
        <div className="text-xs text-muted-foreground">
          Space + 드래그: 패닝 | Ctrl + 휠: 줌
        </div>
      </div>
    </div>
  );
}

// ========================================
// 검토 필요 영역 (오른쪽 패널)
// ========================================

// ========================================
// 숨김 컴포넌트 영역 (오른쪽 패널)
// ========================================

interface HiddenPanelProps {
  components: PopComponentDefinition[];
  selectedComponentId: string | null;
  onSelectComponent: (id: string | null) => void;
  onHideComponent?: (componentId: string) => void;
}

function HiddenPanel({
  components,
  selectedComponentId,
  onSelectComponent,
  onHideComponent,
}: HiddenPanelProps) {
  // 그리드에서 컴포넌트를 드래그하여 이 패널에 드롭하면 숨김 처리
  const [{ isOver, canDrop }, drop] = useDrop(
    () => ({
      accept: DND_ITEM_TYPES.MOVE_COMPONENT,
      drop: (item: { componentId: string; fromHidden?: boolean }) => {
        // 이미 숨김 패널에서 온 아이템은 무시
        if (item.fromHidden) return;
        
        // 숨김 처리
        onHideComponent?.(item.componentId);
        toast.info("컴포넌트가 숨김 처리되었습니다");
      },
      canDrop: (item: { componentId: string; fromHidden?: boolean }) => {
        // 숨김 패널에서 온 아이템은 드롭 불가
        return !item.fromHidden;
      },
      collect: (monitor) => ({
        isOver: monitor.isOver(),
        canDrop: monitor.canDrop(),
      }),
    }),
    [onHideComponent]
  );

  return (
    <div 
      ref={drop}
      className={cn(
        "flex flex-col rounded-lg border-2 border-dashed bg-muted/50 transition-colors",
        isOver && canDrop
          ? "border-input bg-muted/70"
          : "border-input"
      )}
      style={{
        width: "200px",
        maxHeight: "300px",
      }}
    >
      {/* 헤더 */}
      <div className="flex items-center gap-2 border-b border-input bg-muted/50 px-3 py-2 rounded-t-lg">
        <EyeOff className="h-4 w-4 text-muted-foreground" />
        <span className="text-xs font-semibold text-foreground">
          숨김 ({components.length}개)
        </span>
      </div>
      
      {/* 컴포넌트 목록 */}
      <div className="flex-1 overflow-auto p-2 space-y-2">
        {components.map((comp) => (
          <HiddenItem
            key={comp.id}
            component={comp}
            isSelected={selectedComponentId === comp.id}
            onSelect={() => onSelectComponent(comp.id)}
          />
        ))}
      </div>
      
      {/* 안내 문구 */}
      <div className="border-t border-input px-3 py-2 bg-muted/80 rounded-b-lg">
        <p className="text-[10px] text-muted-foreground leading-tight">
          그리드로 드래그하여 다시 표시
        </p>
      </div>
    </div>
  );
}


// ========================================
// 숨김 컴포넌트 아이템 (드래그 가능)
// ========================================

interface HiddenItemProps {
  component: PopComponentDefinition;
  isSelected: boolean;
  onSelect: () => void;
}

function HiddenItem({
  component,
  isSelected,
  onSelect,
}: HiddenItemProps) {
  const [{ isDragging }, drag] = useDrag(
    () => ({
      type: DND_ITEM_TYPES.MOVE_COMPONENT,
      item: { 
        componentId: component.id, 
        originalPosition: component.position,
        fromHidden: true, // 숨김 패널에서 왔음을 표시
      },
      collect: (monitor) => ({
        isDragging: monitor.isDragging(),
      }),
    }),
    [component.id, component.position]
  );

  return (
    <div
      ref={drag}
      className={cn(
        "rounded-md border-2 bg-background p-2 cursor-move transition-all opacity-60",
        isSelected
          ? "border-primary ring-2 ring-primary/30"
          : "border-input hover:border-input",
        isDragging && "opacity-30"
      )}
      onClick={onSelect}
    >
      {/* 컴포넌트 이름 */}
      <div className="flex items-center gap-1 text-xs font-medium text-muted-foreground truncate">
        <EyeOff className="h-3 w-3" />
        {component.label || component.type}
      </div>
      
      {/* 원본 위치 정보 */}
      <div className="text-[10px] text-muted-foreground mt-1">
        원본: {component.position.col}열, {component.position.row}행
      </div>
    </div>
  );
}

// ========================================
// 모달 사이즈 설정 패널
// ========================================

const SIZE_PRESET_ORDER: ModalSizePreset[] = ["sm", "md", "lg", "xl", "full"];

const MODE_LABELS: { mode: GridMode; label: string; icon: typeof Smartphone; width: number }[] = [
  { mode: "mobile_portrait",  label: "모바일 세로",  icon: Smartphone, width: 375 },
  { mode: "mobile_landscape", label: "모바일 가로",  icon: Smartphone, width: 667 },
  { mode: "tablet_portrait",  label: "태블릿 세로",  icon: Tablet,     width: 768 },
  { mode: "tablet_landscape", label: "태블릿 가로",  icon: Monitor,    width: 1024 },
];

function ModalSizeSettingsPanel({
  modal,
  currentMode,
  onUpdate,
}: {
  modal: PopModalDefinition;
  currentMode: GridMode;
  onUpdate: (updates: Partial<PopModalDefinition>) => void;
}) {
  const [isExpanded, setIsExpanded] = useState(false);
  const sizeConfig = modal.sizeConfig || { default: "md" };
  const usePerMode = !!sizeConfig.modeOverrides && Object.keys(sizeConfig.modeOverrides).length > 0;

  const currentModeInfo = MODE_LABELS.find(m => m.mode === currentMode)!;
  const currentModeWidth = currentModeInfo.width;
  const currentModalWidth = resolveModalWidth(
    { default: sizeConfig.default, modeOverrides: sizeConfig.modeOverrides as Record<GridMode, ModalSizePreset> | undefined },
    currentMode,
    currentModeWidth,
  );

  const handleDefaultChange = (preset: ModalSizePreset) => {
    onUpdate({
      sizeConfig: {
        ...sizeConfig,
        default: preset,
      },
    });
  };

  const handleTogglePerMode = () => {
    if (usePerMode) {
      onUpdate({
        sizeConfig: {
          default: sizeConfig.default,
        },
      });
    } else {
      onUpdate({
        sizeConfig: {
          ...sizeConfig,
          modeOverrides: {
            mobile_portrait: sizeConfig.default,
            mobile_landscape: sizeConfig.default,
            tablet_portrait: sizeConfig.default,
            tablet_landscape: sizeConfig.default,
          },
        },
      });
    }
  };

  const handleModeChange = (mode: GridMode, preset: ModalSizePreset) => {
    onUpdate({
      sizeConfig: {
        ...sizeConfig,
        modeOverrides: {
          ...sizeConfig.modeOverrides,
          [mode]: preset,
        },
      },
    });
  };

  return (
    <div className="border-b bg-muted/20">
      {/* 헤더 (항상 표시) */}
      <button
        type="button"
        onClick={() => setIsExpanded(!isExpanded)}
        className="flex w-full items-center justify-between px-4 py-2 hover:bg-muted/30 transition-colors"
      >
        <div className="flex items-center gap-2">
          {isExpanded
            ? <ChevronUp className="h-3.5 w-3.5 text-muted-foreground" />
            : <ChevronDown className="h-3.5 w-3.5 text-muted-foreground" />
          }
          <span className="text-xs font-semibold">{modal.title}</span>
          <span className="rounded bg-primary/10 px-1.5 py-0.5 text-[10px] font-medium text-primary">
            {sizeConfig.default.toUpperCase()}
          </span>
          <span className="text-[10px] text-muted-foreground">
            {currentModalWidth}px / {currentModeWidth}px
          </span>
        </div>
        <span className="text-[10px] text-muted-foreground">{modal.id}</span>
      </button>

      {/* 펼침 영역 */}
      {isExpanded && (
        <div className="px-4 pb-3 space-y-3">
          {/* 기본 사이즈 선택 */}
          <div className="space-y-1">
            <span className="text-[11px] text-muted-foreground font-medium">모달 사이즈</span>
            <div className="flex gap-1">
              {SIZE_PRESET_ORDER.map(preset => {
                const info = MODAL_SIZE_PRESETS[preset];
                return (
                  <button
                    key={preset}
                    type="button"
                    onClick={() => handleDefaultChange(preset)}
                    className={cn(
                      "flex-1 h-8 rounded-md text-xs font-medium transition-colors flex flex-col items-center justify-center gap-0",
                      sizeConfig.default === preset
                        ? "bg-primary text-primary-foreground"
                        : "bg-background border hover:bg-accent"
                    )}
                  >
                    <span className="leading-none">{preset.toUpperCase()}</span>
                    <span className={cn(
                      "text-[9px] leading-none",
                      sizeConfig.default === preset ? "text-primary-foreground/70" : "text-muted-foreground"
                    )}>
                      {preset === "full" ? "100%" : `${info.width}px`}
                    </span>
                  </button>
                );
              })}
            </div>
          </div>

          {/* 모드별 개별 설정 토글 */}
          <div className="flex items-center justify-between">
            <span className="text-[11px] text-muted-foreground">모드별 개별 사이즈</span>
            <button
              type="button"
              onClick={handleTogglePerMode}
              className={cn(
                "relative inline-flex h-5 w-9 items-center rounded-full transition-colors",
                usePerMode ? "bg-primary" : "bg-muted/60"
              )}
            >
              <span
                className={cn(
                  "inline-block h-3.5 w-3.5 rounded-full bg-background transition-transform",
                  usePerMode ? "translate-x-4.5" : "translate-x-0.5"
                )}
              />
            </button>
          </div>

          {/* 모드별 설정 */}
          {usePerMode && (
            <div className="space-y-1.5">
              {MODE_LABELS.map(({ mode, label, icon: Icon }) => {
                const modePreset = sizeConfig.modeOverrides?.[mode] ?? sizeConfig.default;
                return (
                  <div key={mode} className={cn(
                    "flex items-center justify-between rounded-md px-2 py-1",
                    mode === currentMode ? "bg-primary/10 ring-1 ring-primary/30" : ""
                  )}>
                    <div className="flex items-center gap-1.5">
                      <Icon className="h-3.5 w-3.5 text-muted-foreground" />
                      <span className="text-[11px]">{label}</span>
                    </div>
                    <div className="flex gap-0.5">
                      {SIZE_PRESET_ORDER.map(preset => (
                        <button
                          key={preset}
                          type="button"
                          onClick={() => handleModeChange(mode, preset)}
                          className={cn(
                            "h-6 px-1.5 rounded text-[10px] font-medium transition-colors",
                            modePreset === preset
                              ? "bg-primary text-primary-foreground"
                              : "bg-background border hover:bg-accent"
                          )}
                        >
                          {preset.toUpperCase()}
                        </button>
                      ))}
                    </div>
                  </div>
                );
              })}
            </div>
          )}

          {/* 캔버스 축소판 미리보기 */}
          <ModalThumbnailPreview sizeConfig={sizeConfig} currentMode={currentMode} />
        </div>
      )}
    </div>
  );
}

// ========================================
// 모달 사이즈 썸네일 미리보기 (캔버스 축소판 + 모달 오버레이)
// ========================================

function ModalThumbnailPreview({
  sizeConfig,
  currentMode,
}: {
  sizeConfig: { default: ModalSizePreset; modeOverrides?: Partial<Record<GridMode, ModalSizePreset>> };
  currentMode: GridMode;
}) {
  const PREVIEW_WIDTH = 260;
  const ASPECT_RATIO = 0.65;

  const modeInfo = MODE_LABELS.find(m => m.mode === currentMode)!;
  const modeWidth = modeInfo.width;
  const modeHeight = modeWidth * ASPECT_RATIO;

  const scale = PREVIEW_WIDTH / modeWidth;
  const previewHeight = Math.round(modeHeight * scale);

  const modalWidth = resolveModalWidth(
    { default: sizeConfig.default, modeOverrides: sizeConfig.modeOverrides as Record<GridMode, ModalSizePreset> | undefined },
    currentMode,
    modeWidth,
  );
  const scaledModalWidth = Math.min(Math.round(modalWidth * scale), PREVIEW_WIDTH);
  const isFull = modalWidth >= modeWidth;
  const scaledModalHeight = isFull ? previewHeight : Math.round(previewHeight * 0.75);
  const Icon = modeInfo.icon;

  return (
    <div className="space-y-1.5">
      <div className="flex items-center justify-between">
        <span className="text-[11px] text-muted-foreground font-medium">미리보기</span>
        <div className="flex items-center gap-1 text-[10px] text-muted-foreground">
          <Icon className="h-3 w-3" />
          <span>{modeInfo.label}</span>
        </div>
      </div>

      <div
        className="relative mx-auto rounded-md border bg-muted overflow-hidden"
        style={{ width: `${PREVIEW_WIDTH}px`, height: `${previewHeight}px` }}
      >
        {/* 반투명 배경 오버레이 (모달이 열렸을 때의 딤 효과) */}
        <div className="absolute inset-0 bg-black/10" />

        {/* 모달 영역 (가운데 정렬, FULL이면 전체 채움) */}
        <div
          className={cn(
            "absolute border-2 border-primary/60 bg-primary/15",
            isFull ? "rounded-none" : "rounded-sm"
          )}
          style={{
            width: `${scaledModalWidth}px`,
            height: `${scaledModalHeight}px`,
            left: `${(PREVIEW_WIDTH - scaledModalWidth) / 2}px`,
            top: `${(previewHeight - scaledModalHeight) / 2}px`,
          }}
        >
          <div className="absolute top-1 left-1.5 text-[8px] font-medium text-primary/80 leading-none">
            모달
          </div>
        </div>

        {/* 하단 수치 표시 */}
        <div className="absolute bottom-1 right-1.5 rounded bg-black/50 px-1.5 py-0.5 text-[9px] text-white">
          {isFull ? "FULL" : `${modalWidth}px`} / {modeWidth}px
        </div>
      </div>
    </div>
  );
}
