"use client";

import React, { createContext, useContext, useState, useCallback, useRef, useMemo } from "react";

/**
 * SplitPanelResize Context 타입 정의
 * 분할 패널의 드래그 리사이즈 상태를 외부 컴포넌트(버튼 등)와 공유하기 위한 Context
 *
 * 주의: contexts/SplitPanelContext.tsx는 데이터 전달용 Context이고,
 * 이 Context는 드래그 리사이즈 시 버튼 위치 조정을 위한 별도 Context입니다.
 */

/**
 * 분할 패널 정보 (컴포넌트 좌표 기준)
 */
export interface SplitPanelInfo {
  id: string;
  // 분할 패널의 좌표 (스크린 캔버스 기준, px)
  x: number;
  y: number;
  width: number;
  height: number;
  // 좌측 패널 비율 (0-100)
  leftWidthPercent: number;
  // 초기 좌측 패널 비율 (드래그 시작 시점)
  initialLeftWidthPercent: number;
  // 드래그 중 여부
  isDragging: boolean;
  // 패널 유형: "component" = 분할 패널 레이아웃 (버튼만 조정), "canvas" = 캔버스 분할선 (모든 컴포넌트 조정)
  panelType?: "component" | "canvas";
}

export interface SplitPanelResizeContextValue {
  // 등록된 분할 패널들
  splitPanels: Map<string, SplitPanelInfo>;

  // 분할 패널 등록/해제/업데이트
  registerSplitPanel: (id: string, info: Omit<SplitPanelInfo, "id">) => void;
  unregisterSplitPanel: (id: string) => void;
  updateSplitPanel: (id: string, updates: Partial<SplitPanelInfo>) => void;

  // 컴포넌트가 어떤 분할 패널의 좌측 영역 위에 있는지 확인
  // 반환값: { panelId, offsetX } 또는 null
  getOverlappingSplitPanel: (
    componentX: number,
    componentY: number,
    componentWidth: number,
    componentHeight: number,
  ) => { panelId: string; panel: SplitPanelInfo; isInLeftPanel: boolean } | null;

  // 컴포넌트의 조정된 X 좌표 계산
  // 분할 패널 좌측 영역 위에 있으면, 드래그에 따라 조정된 X 좌표 반환
  getAdjustedX: (componentX: number, componentY: number, componentWidth: number, componentHeight: number) => number;

  // 레거시 호환 (단일 분할 패널용)
  leftWidthPercent: number;
  containerRect: DOMRect | null;
  dividerX: number;
  isDragging: boolean;
  splitPanelId: string | null;
  updateLeftWidth: (percent: number) => void;
  updateContainerRect: (rect: DOMRect | null) => void;
  updateDragging: (dragging: boolean) => void;
}

// Context 생성
const SplitPanelResizeContext = createContext<SplitPanelResizeContextValue | null>(null);

/**
 * SplitPanelResize Context Provider
 * 스크린 빌더 레벨에서 감싸서 사용
 */
export const SplitPanelProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  // 등록된 분할 패널들
  const splitPanelsRef = useRef<Map<string, SplitPanelInfo>>(new Map());
  const [, forceUpdate] = useState(0);

  // 레거시 호환용 상태
  const [legacyLeftWidthPercent, setLegacyLeftWidthPercent] = useState(30);
  const [legacyContainerRect, setLegacyContainerRect] = useState<DOMRect | null>(null);
  const [legacyIsDragging, setLegacyIsDragging] = useState(false);
  const [legacySplitPanelId, setLegacySplitPanelId] = useState<string | null>(null);

  // 분할 패널 등록
  const registerSplitPanel = useCallback((id: string, info: Omit<SplitPanelInfo, "id">) => {
    splitPanelsRef.current.set(id, { id, ...info });
    setLegacySplitPanelId(id);
    setLegacyLeftWidthPercent(info.leftWidthPercent);
    forceUpdate((n) => n + 1);
  }, []);

  // 분할 패널 해제
  const unregisterSplitPanel = useCallback(
    (id: string) => {
      splitPanelsRef.current.delete(id);
      if (legacySplitPanelId === id) {
        setLegacySplitPanelId(null);
      }
      forceUpdate((n) => n + 1);
    },
    [legacySplitPanelId],
  );

  // 분할 패널 업데이트
  const updateSplitPanel = useCallback((id: string, updates: Partial<SplitPanelInfo>) => {
    const panel = splitPanelsRef.current.get(id);
    if (panel) {
      const updatedPanel = { ...panel, ...updates };
      splitPanelsRef.current.set(id, updatedPanel);

      // 레거시 호환 상태 업데이트
      if (updates.leftWidthPercent !== undefined) {
        setLegacyLeftWidthPercent(updates.leftWidthPercent);
      }
      if (updates.isDragging !== undefined) {
        setLegacyIsDragging(updates.isDragging);
      }

      forceUpdate((n) => n + 1);
    }
  }, []);

  /**
   * 컴포넌트가 어떤 분할 패널의 좌측 영역 위에 있는지 확인
   */
  const getOverlappingSplitPanel = useCallback(
    (
      componentX: number,
      componentY: number,
      componentWidth: number,
      componentHeight: number,
    ): { panelId: string; panel: SplitPanelInfo; isInLeftPanel: boolean } | null => {
      for (const [panelId, panel] of splitPanelsRef.current) {
        // 컴포넌트의 중심점
        const componentCenterX = componentX + componentWidth / 2;
        const componentCenterY = componentY + componentHeight / 2;

        // 컴포넌트가 분할 패널 영역 내에 있는지 확인
        const isInPanelX = componentCenterX >= panel.x && componentCenterX <= panel.x + panel.width;
        const isInPanelY = componentCenterY >= panel.y && componentCenterY <= panel.y + panel.height;

        if (isInPanelX && isInPanelY) {
          // 좌측 패널의 현재 너비 (px)
          const leftPanelWidth = (panel.width * panel.leftWidthPercent) / 100;
          // 좌측 패널 경계 (분할 패널 기준 상대 좌표)
          const dividerX = panel.x + leftPanelWidth;

          // 컴포넌트 중심이 좌측 패널 내에 있는지 확인
          const isInLeftPanel = componentCenterX < dividerX;

          return { panelId, panel, isInLeftPanel };
        }
      }
      return null;
    },
    [],
  );

  /**
   * 컴포넌트의 조정된 X 좌표 계산
   * 분할 패널 좌측 영역 위에 있으면, 드래그에 따라 조정된 X 좌표 반환
   *
   * 핵심 로직:
   * - 버튼의 원래 X 좌표가 초기 좌측 패널 너비 내에서 어느 비율에 있는지 계산
   * - 드래그로 좌측 패널 너비가 바뀌면, 같은 비율을 유지하도록 X 좌표 조정
   */
  const getAdjustedX = useCallback(
    (componentX: number, componentY: number, componentWidth: number, componentHeight: number): number => {
      const overlap = getOverlappingSplitPanel(componentX, componentY, componentWidth, componentHeight);

      if (!overlap || !overlap.isInLeftPanel) {
        // 분할 패널 위에 없거나, 우측 패널 위에 있으면 원래 위치 유지
        return componentX;
      }

      const { panel } = overlap;

      // 초기 좌측 패널 너비 (설정된 splitRatio 기준)
      const initialLeftPanelWidth = (panel.width * panel.initialLeftWidthPercent) / 100;
      // 현재 좌측 패널 너비 (드래그로 변경된 값)
      const currentLeftPanelWidth = (panel.width * panel.leftWidthPercent) / 100;

      // 변화가 없으면 원래 위치 반환
      if (Math.abs(initialLeftPanelWidth - currentLeftPanelWidth) < 1) {
        return componentX;
      }

      // 컴포넌트의 분할 패널 내 상대 X 좌표
      const relativeX = componentX - panel.x;

      // 좌측 패널 내에서의 비율 (0~1)
      const ratioInLeftPanel = relativeX / initialLeftPanelWidth;

      // 조정된 상대 X 좌표 = 원래 비율 * 현재 좌측 패널 너비
      const adjustedRelativeX = ratioInLeftPanel * currentLeftPanelWidth;

      // 절대 X 좌표로 변환
      const adjustedX = panel.x + adjustedRelativeX;

      console.log("📍 [SplitPanel] 버튼 위치 조정:", {
        componentX,
        panelX: panel.x,
        relativeX,
        initialLeftPanelWidth,
        currentLeftPanelWidth,
        ratioInLeftPanel,
        adjustedX,
        delta: adjustedX - componentX,
      });

      return adjustedX;
    },
    [getOverlappingSplitPanel],
  );

  // 레거시 호환 - dividerX 계산
  const legacyDividerX = legacyContainerRect ? (legacyContainerRect.width * legacyLeftWidthPercent) / 100 : 0;

  // 레거시 호환 함수들
  const updateLeftWidth = useCallback((percent: number) => {
    setLegacyLeftWidthPercent(percent);
    // 첫 번째 분할 패널 업데이트
    const firstPanelId = splitPanelsRef.current.keys().next().value;
    if (firstPanelId) {
      const panel = splitPanelsRef.current.get(firstPanelId);
      if (panel) {
        splitPanelsRef.current.set(firstPanelId, { ...panel, leftWidthPercent: percent });
      }
    }
    forceUpdate((n) => n + 1);
  }, []);

  const updateContainerRect = useCallback((rect: DOMRect | null) => {
    setLegacyContainerRect(rect);
  }, []);

  const updateDragging = useCallback((dragging: boolean) => {
    setLegacyIsDragging(dragging);
    // 첫 번째 분할 패널 업데이트
    const firstPanelId = splitPanelsRef.current.keys().next().value;
    if (firstPanelId) {
      const panel = splitPanelsRef.current.get(firstPanelId);
      if (panel) {
        // 드래그 시작 시 초기 비율 저장
        const updates: Partial<SplitPanelInfo> = { isDragging: dragging };
        if (dragging) {
          updates.initialLeftWidthPercent = panel.leftWidthPercent;
        }
        splitPanelsRef.current.set(firstPanelId, { ...panel, ...updates });
      }
    }
    forceUpdate((n) => n + 1);
  }, []);

  const value = useMemo<SplitPanelResizeContextValue>(
    () => ({
      splitPanels: splitPanelsRef.current,
      registerSplitPanel,
      unregisterSplitPanel,
      updateSplitPanel,
      getOverlappingSplitPanel,
      getAdjustedX,
      // 레거시 호환
      leftWidthPercent: legacyLeftWidthPercent,
      containerRect: legacyContainerRect,
      dividerX: legacyDividerX,
      isDragging: legacyIsDragging,
      splitPanelId: legacySplitPanelId,
      updateLeftWidth,
      updateContainerRect,
      updateDragging,
    }),
    [
      registerSplitPanel,
      unregisterSplitPanel,
      updateSplitPanel,
      getOverlappingSplitPanel,
      getAdjustedX,
      legacyLeftWidthPercent,
      legacyContainerRect,
      legacyDividerX,
      legacyIsDragging,
      legacySplitPanelId,
      updateLeftWidth,
      updateContainerRect,
      updateDragging,
    ],
  );

  return <SplitPanelResizeContext.Provider value={value}>{children}</SplitPanelResizeContext.Provider>;
};

/**
 * SplitPanelResize Context 사용 훅
 * 분할 패널의 드래그 리사이즈 상태를 구독합니다.
 */
export const useSplitPanel = (): SplitPanelResizeContextValue => {
  const context = useContext(SplitPanelResizeContext);

  // Context가 없으면 기본값 반환 (Provider 외부에서 사용 시)
  if (!context) {
    return {
      splitPanels: new Map(),
      registerSplitPanel: () => {},
      unregisterSplitPanel: () => {},
      updateSplitPanel: () => {},
      getOverlappingSplitPanel: () => null,
      getAdjustedX: (x) => x,
      leftWidthPercent: 30,
      containerRect: null,
      dividerX: 0,
      isDragging: false,
      splitPanelId: null,
      updateLeftWidth: () => {},
      updateContainerRect: () => {},
      updateDragging: () => {},
    };
  }

  return context;
};

/**
 * 컴포넌트의 조정된 위치를 계산하는 훅
 * 분할 패널 좌측 영역 위에 있으면, 드래그에 따라 X 좌표가 조정됨
 *
 * @param componentX - 컴포넌트의 X 좌표 (px)
 * @param componentY - 컴포넌트의 Y 좌표 (px)
 * @param componentWidth - 컴포넌트 너비 (px)
 * @param componentHeight - 컴포넌트 높이 (px)
 * @returns 조정된 X 좌표와 관련 정보
 */
export const useAdjustedComponentPosition = (
  componentX: number,
  componentY: number,
  componentWidth: number,
  componentHeight: number,
) => {
  const context = useSplitPanel();

  const adjustedX = context.getAdjustedX(componentX, componentY, componentWidth, componentHeight);
  const overlap = context.getOverlappingSplitPanel(componentX, componentY, componentWidth, componentHeight);

  return {
    adjustedX,
    isInSplitPanel: !!overlap,
    isInLeftPanel: overlap?.isInLeftPanel ?? false,
    isDragging: overlap?.panel.isDragging ?? false,
    panelId: overlap?.panelId ?? null,
  };
};

/**
 * 버튼 등 외부 컴포넌트에서 분할 패널 좌측 영역 내 위치를 계산하는 훅 (레거시 호환)
 */
export const useAdjustedPosition = (originalXPercent: number) => {
  const { leftWidthPercent, containerRect, dividerX, isDragging } = useSplitPanel();

  const isInLeftPanel = originalXPercent <= leftWidthPercent;
  const adjustedXPercent = isInLeftPanel ? (originalXPercent / 100) * leftWidthPercent : originalXPercent;
  const adjustedXPx = containerRect ? (containerRect.width * adjustedXPercent) / 100 : 0;

  return {
    adjustedXPercent,
    adjustedXPx,
    isInLeftPanel,
    isDragging,
    dividerX,
    containerRect,
    leftWidthPercent,
  };
};

/**
 * 버튼이 좌측 패널 위에 배치되었을 때, 드래그에 따라 위치가 조정되는 스타일을 반환하는 훅 (레거시 호환)
 */
export const useSplitPanelAwarePosition = (
  initialLeftPercent: number,
  options?: {
    followDivider?: boolean;
    offset?: number;
  },
) => {
  const { leftWidthPercent, containerRect, dividerX, isDragging } = useSplitPanel();
  const { followDivider = false, offset = 0 } = options || {};

  if (followDivider) {
    return {
      left: containerRect ? `${dividerX + offset}px` : `${leftWidthPercent}%`,
      transition: isDragging ? "none" : "left 0.15s ease-out",
    };
  }

  const adjustedLeft = (initialLeftPercent / 100) * leftWidthPercent;

  return {
    left: `${adjustedLeft}%`,
    transition: isDragging ? "none" : "left 0.15s ease-out",
  };
};

export default SplitPanelResizeContext;
