"use client";

import React, { forwardRef, useState, useCallback, useMemo, useEffect } from "react";
import { DashboardElement, ElementType, ElementSubtype, DragData } from "./types";
import { CanvasElement } from "./CanvasElement";
import {
  GRID_CONFIG,
  snapToGrid,
  calculateGridConfig,
  calculateVerticalGuidelines,
  calculateHorizontalGuidelines,
  calculateBoxSize,
  magneticSnap,
} from "./gridUtils";
import { resolveAllCollisions } from "./collisionUtils";

interface DashboardCanvasProps {
  elements: DashboardElement[];
  selectedElement: string | null;
  selectedElements?: string[]; // 🔥 다중 선택된 요소 ID 배열
  onCreateElement: (type: ElementType, subtype: ElementSubtype, x: number, y: number) => void;
  onUpdateElement: (id: string, updates: Partial<DashboardElement>) => void;
  onRemoveElement: (id: string) => void;
  onSelectElement: (id: string | null) => void;
  onSelectMultiple?: (ids: string[]) => void; // 🔥 다중 선택 핸들러
  onConfigureElement?: (element: DashboardElement) => void;
  backgroundColor?: string;
  canvasWidth?: number;
  canvasHeight?: number;
}

/**
 * 대시보드 캔버스 컴포넌트
 * - 드래그 앤 드롭 영역
 * - 12 컬럼 그리드 배경
 * - 스냅 기능
 * - 요소 배치 및 관리
 */
export const DashboardCanvas = forwardRef<HTMLDivElement, DashboardCanvasProps>(
  (
    {
      elements,
      selectedElement,
      selectedElements = [],
      onCreateElement,
      onUpdateElement,
      onRemoveElement,
      onSelectElement,
      onSelectMultiple,
      onConfigureElement,
      backgroundColor = "transparent",
      canvasWidth = 1560,
      canvasHeight = 768,
    },
    ref,
  ) => {
    const [isDragOver, setIsDragOver] = useState(false);

    // 🔥 선택 박스 상태
    const [selectionBox, setSelectionBox] = useState<{
      startX: number;
      startY: number;
      endX: number;
      endY: number;
    } | null>(null);
    const [isSelecting, setIsSelecting] = useState(false);
    const [justSelected, setJustSelected] = useState(false); // 🔥 방금 선택했는지 플래그
    const [isDraggingAny, setIsDraggingAny] = useState(false); // 🔥 현재 드래그 중인지 플래그

    // 🔥 다중 선택된 위젯들의 임시 위치 (드래그 중 시각적 피드백)
    const [multiDragOffsets, setMultiDragOffsets] = useState<Record<string, { x: number; y: number }>>({});

    // 🔥 선택 박스 드래그 중 자동 스크롤
    const lastMouseYForSelectionRef = React.useRef<number>(window.innerHeight / 2);
    const selectionAutoScrollFrameRef = React.useRef<number | null>(null);

    // 현재 캔버스 크기에 맞는 그리드 설정 계산
    const gridConfig = useMemo(() => calculateGridConfig(canvasWidth), [canvasWidth]);
    const cellSize = gridConfig.CELL_SIZE;

    // 🔥 그리드 박스 시스템 - 12개 박스가 캔버스 너비에 꽉 차게
    const verticalGuidelines = useMemo(() => calculateVerticalGuidelines(canvasWidth), [canvasWidth]);
    const horizontalGuidelines = useMemo(
      () => calculateHorizontalGuidelines(canvasHeight, canvasWidth),
      [canvasHeight, canvasWidth],
    );
    const boxSize = useMemo(() => calculateBoxSize(canvasWidth), [canvasWidth]);

    // 충돌 방지 기능이 포함된 업데이트 핸들러
    const handleUpdateWithCollisionDetection = useCallback(
      (id: string, updates: Partial<DashboardElement>) => {
        // position이나 size가 아닌 다른 속성 업데이트는 충돌 감지 없이 바로 처리
        if (!updates.position && !updates.size) {
          onUpdateElement(id, updates);
          return;
        }

        // 업데이트할 요소 찾기
        const elementIndex = elements.findIndex((el) => el.id === id);
        if (elementIndex === -1) {
          onUpdateElement(id, updates);
          return;
        }

        // position이나 size와 다른 속성이 함께 있으면 분리해서 처리
        const positionSizeUpdates: any = {};
        const otherUpdates: any = {};

        Object.keys(updates).forEach((key) => {
          if (key === "position" || key === "size") {
            positionSizeUpdates[key] = (updates as any)[key];
          } else {
            otherUpdates[key] = (updates as any)[key];
          }
        });

        // 다른 속성들은 먼저 바로 업데이트
        if (Object.keys(otherUpdates).length > 0) {
          onUpdateElement(id, otherUpdates);
        }

        // position/size가 없으면 여기서 종료
        if (Object.keys(positionSizeUpdates).length === 0) {
          return;
        }

        // 임시로 업데이트된 요소 배열 생성
        const updatedElements = elements.map((el) =>
          el.id === id
            ? {
                ...el,
                ...positionSizeUpdates,
                position: positionSizeUpdates.position || el.position,
                size: positionSizeUpdates.size || el.size,
              }
            : el,
        );

        // 서브 그리드 크기 계산 (cellSize / 3)
        const subGridSize = Math.floor(cellSize / 3);

        // 충돌 해결 (서브 그리드 단위로 스냅 및 충돌 감지)
        const resolvedElements = resolveAllCollisions(updatedElements, id, subGridSize, canvasWidth, cellSize);

        // 변경된 요소들만 업데이트
        resolvedElements.forEach((resolvedEl, idx) => {
          const originalEl = elements[idx];
          if (
            resolvedEl.position.x !== originalEl.position.x ||
            resolvedEl.position.y !== originalEl.position.y ||
            resolvedEl.size.width !== originalEl.size.width ||
            resolvedEl.size.height !== originalEl.size.height
          ) {
            onUpdateElement(resolvedEl.id, {
              position: resolvedEl.position,
              size: resolvedEl.size,
            });
          }
        });
      },
      [elements, onUpdateElement, cellSize, canvasWidth],
    );

    // 드래그 오버 처리
    const handleDragOver = useCallback((e: React.DragEvent) => {
      e.preventDefault();
      e.dataTransfer.dropEffect = "copy";
      setIsDragOver(true);
    }, []);

    // 드래그 리브 처리
    const handleDragLeave = useCallback((e: React.DragEvent) => {
      if (e.currentTarget === e.target) {
        setIsDragOver(false);
      }
    }, []);

    // 드롭 처리 (그리드 스냅 적용)
    const handleDrop = useCallback(
      (e: React.DragEvent) => {
        e.preventDefault();
        setIsDragOver(false);

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

          if (!ref || typeof ref === "function") return;

          const rect = ref.current?.getBoundingClientRect();
          if (!rect) return;

          // 캔버스 스크롤을 고려한 정확한 위치 계산
          const rawX = e.clientX - rect.left + (ref.current?.scrollLeft || 0);
          const rawY = e.clientY - rect.top + (ref.current?.scrollTop || 0);

          // 자석 스냅 적용
          let snappedX = magneticSnap(rawX, verticalGuidelines);
          let snappedY = magneticSnap(rawY, horizontalGuidelines);

          // X 좌표가 캔버스 너비를 벗어나지 않도록 제한 (최소 2칸 너비 보장)
          const minElementWidth = cellSize * 2 + GRID_CONFIG.GAP;
          const maxX = canvasWidth - minElementWidth;
          snappedX = Math.max(0, Math.min(snappedX, maxX));

          onCreateElement(dragData.type, dragData.subtype, snappedX, snappedY);
        } catch {
          // 드롭 데이터 파싱 오류 무시
        }
      },
      [ref, onCreateElement, canvasWidth, cellSize, verticalGuidelines, horizontalGuidelines],
    );

    // 🔥 선택 박스 드래그 시작
    const handleMouseDown = useCallback(
      (e: React.MouseEvent) => {
        // 🔥 위젯 내부 클릭이 아닌 경우만 (data-element-id가 없는 경우)
        const target = e.target as HTMLElement;
        const isWidget = target.closest("[data-element-id]");

        if (isWidget) {
          // console.log("🚫 위젯 내부 클릭 - 선택 박스 시작 안함");
          return;
        }

        // console.log("✅ 빈 공간 클릭 - 선택 박스 시작");

        if (!ref || typeof ref === "function") return;
        const rect = ref.current?.getBoundingClientRect();
        if (!rect) return;

        const x = e.clientX - rect.left + (ref.current?.scrollLeft || 0);
        const y = e.clientY - rect.top + (ref.current?.scrollTop || 0);

        // 🔥 일단 시작 위치만 저장 (아직 isSelecting은 false)
        setSelectionBox({ startX: x, startY: y, endX: x, endY: y });
      },
      [ref],
    );

    // 🔥 선택 박스 드래그 종료
    const handleMouseUp = useCallback(() => {
      if (!isSelecting || !selectionBox) {
        setIsSelecting(false);
        setSelectionBox(null);
        return;
      }

      if (!onSelectMultiple) {
        setIsSelecting(false);
        setSelectionBox(null);
        return;
      }

      // 선택 박스 영역 계산
      const minX = Math.min(selectionBox.startX, selectionBox.endX);
      const maxX = Math.max(selectionBox.startX, selectionBox.endX);
      const minY = Math.min(selectionBox.startY, selectionBox.endY);
      const maxY = Math.max(selectionBox.startY, selectionBox.endY);

      // console.log("🔍 선택 박스:", { minX, maxX, minY, maxY });

      // 선택 박스 안에 있는 요소들 찾기 (70% 이상 겹치면 선택)
      const selectedIds = elements
        .filter((el) => {
          const elLeft = el.position.x;
          const elRight = el.position.x + el.size.width;
          const elTop = el.position.y;
          const elBottom = el.position.y + el.size.height;

          // 겹치는 영역 계산
          const overlapLeft = Math.max(elLeft, minX);
          const overlapRight = Math.min(elRight, maxX);
          const overlapTop = Math.max(elTop, minY);
          const overlapBottom = Math.min(elBottom, maxY);

          // 겹치는 영역이 없으면 false
          if (overlapRight < overlapLeft || overlapBottom < overlapTop) {
            return false;
          }

          // 겹치는 영역의 넓이
          const overlapArea = (overlapRight - overlapLeft) * (overlapBottom - overlapTop);

          // 요소의 전체 넓이
          const elementArea = el.size.width * el.size.height;

          // 70% 이상 겹치면 선택
          const overlapPercentage = overlapArea / elementArea;

          // console.log(`📦 요소 ${el.id}:`, {
          //   position: el.position,
          //   size: el.size,
          //   overlapPercentage: (overlapPercentage * 100).toFixed(1) + "%",
          //   selected: overlapPercentage >= 0.7,
          // });

          return overlapPercentage >= 0.7;
        })
        .map((el) => el.id);

      // console.log("✅ 선택된 요소:", selectedIds);

      if (selectedIds.length > 0) {
        onSelectMultiple(selectedIds);
        setJustSelected(true); // 🔥 방금 선택했음을 표시
        setTimeout(() => setJustSelected(false), 100); // 100ms 후 플래그 해제
      } else {
        onSelectMultiple([]); // 빈 배열도 전달
      }

      setIsSelecting(false);
      setSelectionBox(null);
    }, [isSelecting, selectionBox, elements, onSelectMultiple]);

    // 🔥 document 레벨에서 마우스 이동/해제 감지 (위젯 위에서도 작동)
    useEffect(() => {
      if (!selectionBox) return;

      const handleDocumentMouseMove = (e: MouseEvent) => {
        if (!ref || typeof ref === "function") return;
        const rect = ref.current?.getBoundingClientRect();
        if (!rect) return;

        const x = e.clientX - rect.left + (ref.current?.scrollLeft || 0);
        const y = e.clientY - rect.top + (ref.current?.scrollTop || 0);

        // 🔥 자동 스크롤을 위한 마우스 Y 위치 저장
        lastMouseYForSelectionRef.current = e.clientY;

        // console.log("🖱️ 마우스 이동:", { x, y, startX: selectionBox.startX, startY: selectionBox.startY, isSelecting });

        // 🔥 selectionBox가 있지만 아직 isSelecting이 false인 경우 (드래그 시작 대기)
        if (!isSelecting) {
          const deltaX = Math.abs(x - selectionBox.startX);
          const deltaY = Math.abs(y - selectionBox.startY);

          // console.log("📏 이동 거리:", { deltaX, deltaY });

          // 🔥 5px 이상 움직이면 선택 박스 활성화 (위젯 드래그와 구분)
          if (deltaX > 5 || deltaY > 5) {
            // console.log("🎯 선택 박스 활성화 (5px 이상 이동)");
            setIsSelecting(true);
          }
          return;
        }

        // 🔥 선택 박스 업데이트
        // console.log("📦 선택 박스 업데이트:", { startX: selectionBox.startX, startY: selectionBox.startY, endX: x, endY: y });
        setSelectionBox((prev) => (prev ? { ...prev, endX: x, endY: y } : null));
      };

      const handleDocumentMouseUp = () => {
        // console.log("🖱️ 마우스 업 - handleMouseUp 호출");
        handleMouseUp();
      };

      document.addEventListener("mousemove", handleDocumentMouseMove);
      document.addEventListener("mouseup", handleDocumentMouseUp);

      return () => {
        document.removeEventListener("mousemove", handleDocumentMouseMove);
        document.removeEventListener("mouseup", handleDocumentMouseUp);
      };
    }, [selectionBox, isSelecting, ref, handleMouseUp]);

    // 🔥 선택 박스 드래그 중 자동 스크롤
    useEffect(() => {
      if (!isSelecting) {
        // console.log("❌ 자동 스크롤 비활성화: isSelecting =", isSelecting);
        return;
      }

      // console.log("✅ 자동 스크롤 활성화: isSelecting =", isSelecting);

      const scrollSpeed = 3;
      const scrollThreshold = 100;
      let animationFrameId: number;
      let lastTime = performance.now();

      const autoScrollLoop = (currentTime: number) => {
        const viewportHeight = window.innerHeight;
        const lastMouseY = lastMouseYForSelectionRef.current;

        let shouldScroll = false;
        let scrollDirection = 0;

        if (lastMouseY < scrollThreshold) {
          shouldScroll = true;
          scrollDirection = -scrollSpeed;
          // console.log("⬆️ 위로 스크롤 (선택 박스):", { lastMouseY, scrollThreshold });
        } else if (lastMouseY > viewportHeight - scrollThreshold) {
          shouldScroll = true;
          scrollDirection = scrollSpeed;
          // console.log("⬇️ 아래로 스크롤 (선택 박스):", { lastMouseY, boundary: viewportHeight - scrollThreshold });
        }

        const deltaTime = currentTime - lastTime;

        if (shouldScroll && deltaTime >= 10) {
          window.scrollBy(0, scrollDirection);
          // console.log("✅ 스크롤 실행 (선택 박스):", { scrollDirection, deltaTime });
          lastTime = currentTime;
        }

        animationFrameId = requestAnimationFrame(autoScrollLoop);
      };

      animationFrameId = requestAnimationFrame(autoScrollLoop);
      selectionAutoScrollFrameRef.current = animationFrameId;

      return () => {
        if (animationFrameId) {
          cancelAnimationFrame(animationFrameId);
        }
        // console.log("🛑 자동 스크롤 정리");
      };
    }, [isSelecting]);

    // 캔버스 클릭 시 선택 해제
    const handleCanvasClick = useCallback(
      (e: React.MouseEvent) => {
        // 🔥 방금 선택했거나 드래그 중이면 클릭 이벤트 무시 (선택 해제 방지)
        if (justSelected || isDraggingAny) {
          // console.log("🚫 방금 선택했거나 드래그 중이므로 클릭 이벤트 무시");
          return;
        }

        if (e.target === e.currentTarget) {
          // console.log("✅ 빈 공간 클릭 - 선택 해제");
          onSelectElement(null);
          if (onSelectMultiple) {
            onSelectMultiple([]);
          }
        }
      },
      [onSelectElement, onSelectMultiple, justSelected, isDraggingAny],
    );

    // 동적 그리드 크기 계산
    const cellWithGap = cellSize + GRID_CONFIG.GAP;
    const gridSize = `${cellWithGap}px ${cellWithGap}px`;

    // 서브그리드 크기 계산 (gridConfig에서 정확하게 계산된 값 사용)
    const subGridSize = gridConfig.SUB_GRID_SIZE;

    // 12개 컬럼 구분선 위치 계산
    const columnLines = Array.from({ length: GRID_CONFIG.COLUMNS + 1 }, (_, i) => i * cellWithGap);

    // 🔥 선택 박스 스타일 계산
    const selectionBoxStyle = useMemo(() => {
      if (!selectionBox) return null;

      const minX = Math.min(selectionBox.startX, selectionBox.endX);
      const maxX = Math.max(selectionBox.startX, selectionBox.endX);
      const minY = Math.min(selectionBox.startY, selectionBox.endY);
      const maxY = Math.max(selectionBox.startY, selectionBox.endY);

      return {
        left: `${minX}px`,
        top: `${minY}px`,
        width: `${maxX - minX}px`,
        height: `${maxY - minY}px`,
      };
    }, [selectionBox]);

    return (
      <div
        ref={ref}
        className={`dashboard-canvas relative w-full ${isDragOver ? "bg-primary/5" : ""} `}
        style={{
          backgroundColor,
          height: `${canvasHeight}px`,
          minHeight: `${canvasHeight}px`,
          cursor: isSelecting ? "crosshair" : "default",
        }}
        onDragOver={handleDragOver}
        onDragLeave={handleDragLeave}
        onDrop={handleDrop}
        onClick={handleCanvasClick}
        onMouseDown={handleMouseDown}
      >
        {/* 12개 컬럼 메인 구분선 - 주석 처리 (서브그리드만 사용) */}
        {/* {columnLines.map((x, i) => (
          <div
            key={`col-${i}`}
            className="pointer-events-none absolute top-0 h-full"
            style={{
              left: `${x}px`,
              width: "1px",
              backgroundColor: i === 0 || i === GRID_CONFIG.COLUMNS ? "rgba(59, 130, 246, 0.3)" : "rgba(59, 130, 246, 0.15)",
              zIndex: 0,
            }}
          />
        ))} */}
        {/* 그리드 박스들 (12px 간격, 캔버스 너비에 꽉 차게, 마지막 행 제외) */}
        {verticalGuidelines.map((x, xIdx) =>
          horizontalGuidelines.slice(0, -1).map((y, yIdx) => (
            <div
              key={`grid-box-${xIdx}-${yIdx}`}
              className="pointer-events-none absolute"
              style={{
                left: `${x}px`,
                top: `${y}px`,
                width: `${boxSize}px`,
                height: `${boxSize}px`,
                backgroundColor: "hsl(var(--background))",
                boxShadow: "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)",
                zIndex: 0,
              }}
            />
          )),
        )}
        {/* 배치된 요소들 렌더링 */}
        {elements.length === 0 && (
          <div className="pointer-events-none absolute inset-0 flex items-center justify-center text-muted-foreground">
            <div className="text-center">
              <div className="text-sm">상단 메뉴에서 차트나 위젯을 선택하세요</div>
            </div>
          </div>
        )}
        {elements.map((element) => (
          <CanvasElement
            key={element.id}
            element={element}
            isSelected={selectedElement === element.id || selectedElements.includes(element.id)}
            selectedElements={selectedElements}
            allElements={elements}
            multiDragOffset={multiDragOffsets[element.id]}
            cellSize={cellSize}
            subGridSize={subGridSize}
            canvasWidth={canvasWidth}
            verticalGuidelines={verticalGuidelines}
            horizontalGuidelines={horizontalGuidelines}
            onUpdate={handleUpdateWithCollisionDetection}
            onUpdateMultiple={(updates) => {
              // 🔥 여러 요소 동시 업데이트 (충돌 감지 건너뛰기)
              updates.forEach(({ id, updates: elementUpdates }) => {
                onUpdateElement(id, elementUpdates);
              });
            }}
            onMultiDragStart={(draggedId, initialOffsets) => {
              // 🔥 다중 드래그 시작 - 초기 오프셋 저장
              setMultiDragOffsets(initialOffsets);
              setIsDraggingAny(true);
            }}
            onMultiDragMove={(draggedElement, tempPosition) => {
              // 🔥 다중 드래그 중 - 다른 위젯들의 위치 실시간 업데이트
              if (selectedElements.length > 1 && selectedElements.includes(draggedElement.id)) {
                const newOffsets: Record<string, { x: number; y: number }> = {};
                selectedElements.forEach((id) => {
                  if (id !== draggedElement.id) {
                    const targetElement = elements.find((el) => el.id === id);
                    if (targetElement) {
                      const relativeX = targetElement.position.x - draggedElement.position.x;
                      const relativeY = targetElement.position.y - draggedElement.position.y;
                      newOffsets[id] = {
                        x: tempPosition.x + relativeX - targetElement.position.x,
                        y: tempPosition.y + relativeY - targetElement.position.y,
                      };
                    }
                  }
                });
                setMultiDragOffsets(newOffsets);
              }
            }}
            onMultiDragEnd={() => {
              // 🔥 다중 드래그 종료 - 오프셋 초기화
              setMultiDragOffsets({});
              setIsDraggingAny(false);
            }}
            onRemove={onRemoveElement}
            onSelect={onSelectElement}
          />
        ))}

        {/* 🔥 선택 박스 렌더링 */}
        {selectionBox && selectionBoxStyle && (
          <div
            className="pointer-events-none absolute"
            style={{
              ...selectionBoxStyle,
              border: "2px dashed #3b82f6",
              backgroundColor: "rgba(59, 130, 246, 0.1)",
              zIndex: 9999,
            }}
          />
        )}
      </div>
    );
  },
);

DashboardCanvas.displayName = "DashboardCanvas";
