import React, { createContext, useContext, useState, useCallback, ReactNode, useMemo } from "react";
import { LayerDefinition, LayerType, ComponentData } from "@/types/screen-management";
import { v4 as uuidv4 } from "uuid";

interface LayerContextType {
  // 레이어 상태
  layers: LayerDefinition[];
  activeLayerId: string | null;
  activeLayer: LayerDefinition | null;

  // 레이어 관리
  setLayers: (layers: LayerDefinition[]) => void;
  setActiveLayerId: (id: string | null) => void;
  addLayer: (type: LayerType, name?: string) => void;
  removeLayer: (id: string) => void;
  updateLayer: (id: string, updates: Partial<LayerDefinition>) => void;
  moveLayer: (dragIndex: number, hoverIndex: number) => void;
  toggleLayerVisibility: (id: string) => void;
  toggleLayerLock: (id: string) => void;
  getLayerById: (id: string) => LayerDefinition | undefined;

  // 컴포넌트 관리 (레이어별)
  addComponentToLayer: (layerId: string, component: ComponentData) => void;
  removeComponentFromLayer: (layerId: string, componentId: string) => void;
  updateComponentInLayer: (layerId: string, componentId: string, updates: Partial<ComponentData>) => void;
  moveComponentToLayer: (componentId: string, fromLayerId: string, toLayerId: string) => void;

  // 컴포넌트 조회
  getAllComponents: () => ComponentData[];
  getComponentById: (componentId: string) => { component: ComponentData; layerId: string } | null;
  getComponentsInActiveLayer: () => ComponentData[];

  // 레이어 가시성 (런타임용)
  runtimeVisibleLayers: string[];
  setRuntimeVisibleLayers: React.Dispatch<React.SetStateAction<string[]>>;
  showLayer: (layerId: string) => void;
  hideLayer: (layerId: string) => void;
  toggleLayerRuntime: (layerId: string) => void;
}

const LayerContext = createContext<LayerContextType | undefined>(undefined);

export const useLayer = () => {
  const context = useContext(LayerContext);
  if (!context) {
    throw new Error("useLayer must be used within a LayerProvider");
  }
  return context;
};

// LayerProvider가 없을 때 사용할 기본 컨텍스트 (선택적 사용)
export const useLayerOptional = () => {
  return useContext(LayerContext);
};

interface LayerProviderProps {
  children: ReactNode;
  initialLayers?: LayerDefinition[];
  onLayersChange?: (layers: LayerDefinition[]) => void;
  onActiveLayerChange?: (activeLayerId: string | null) => void; // 🆕 활성 레이어 변경 콜백
}

// 기본 레이어 생성 헬퍼
export const createDefaultLayer = (components?: ComponentData[]): LayerDefinition => ({
  id: "default-layer",
  name: "기본 레이어",
  type: "base",
  zIndex: 0,
  isVisible: true,
  isLocked: false,
  components: components || [],
});

export const LayerProvider: React.FC<LayerProviderProps> = ({
  children,
  initialLayers = [],
  onLayersChange,
  onActiveLayerChange,
}) => {
  // 초기 레이어가 없으면 기본 레이어 생성
  const effectiveInitialLayers = initialLayers.length > 0 ? initialLayers : [createDefaultLayer()];

  const [layers, setLayersState] = useState<LayerDefinition[]>(effectiveInitialLayers);
  const [activeLayerIdState, setActiveLayerIdState] = useState<string | null>(
    effectiveInitialLayers.length > 0 ? effectiveInitialLayers[0].id : null,
  );

  // 🆕 활성 레이어 변경 시 콜백 호출
  const setActiveLayerId = useCallback(
    (id: string | null) => {
      setActiveLayerIdState(id);
      onActiveLayerChange?.(id);
    },
    [onActiveLayerChange],
  );

  // 활성 레이어 ID (내부 상태 사용)
  const activeLayerId = activeLayerIdState;

  // 런타임 가시성 상태 (편집기에서의 isVisible과 별개)
  const [runtimeVisibleLayers, setRuntimeVisibleLayers] = useState<string[]>(
    effectiveInitialLayers.filter((l) => l.isVisible).map((l) => l.id),
  );

  // 레이어 변경 시 콜백 호출
  const setLayers = useCallback(
    (newLayers: LayerDefinition[]) => {
      setLayersState(newLayers);
      onLayersChange?.(newLayers);
    },
    [onLayersChange],
  );

  // 활성 레이어 계산
  const activeLayer = useMemo(() => {
    return layers.find((l) => l.id === activeLayerId) || null;
  }, [layers, activeLayerId]);

  const addLayer = useCallback(
    (type: LayerType, name?: string) => {
      const newLayer: LayerDefinition = {
        id: uuidv4(),
        name: name || `새 레이어 ${layers.length + 1}`,
        type,
        zIndex: layers.length,
        isVisible: true,
        isLocked: false,
        components: [],
        // 모달/드로어 기본 설정
        ...(type === "modal" || type === "drawer"
          ? {
              overlayConfig: {
                backdrop: true,
                closeOnBackdropClick: true,
                width: type === "drawer" ? "320px" : "600px",
                height: type === "drawer" ? "100%" : "auto",
              },
            }
          : {}),
      };

      setLayers([...layers, newLayer]);
      setActiveLayerId(newLayer.id);
      // 새 레이어는 런타임에서도 기본적으로 표시
      setRuntimeVisibleLayers((prev) => [...prev, newLayer.id]);
    },
    [layers, setLayers],
  );

  const removeLayer = useCallback(
    (id: string) => {
      // 기본 레이어는 삭제 불가
      const layer = layers.find((l) => l.id === id);
      if (layer?.type === "base") {
        console.warn("기본 레이어는 삭제할 수 없습니다.");
        return;
      }

      const filtered = layers.filter((layer) => layer.id !== id);
      setLayers(filtered);

      if (activeLayerId === id) {
        setActiveLayerId(filtered.length > 0 ? filtered[0].id : null);
      }

      setRuntimeVisibleLayers((prev) => prev.filter((lid) => lid !== id));
    },
    [layers, activeLayerId, setLayers],
  );

  const updateLayer = useCallback(
    (id: string, updates: Partial<LayerDefinition>) => {
      setLayers(layers.map((layer) => (layer.id === id ? { ...layer, ...updates } : layer)));
    },
    [layers, setLayers],
  );

  const moveLayer = useCallback(
    (dragIndex: number, hoverIndex: number) => {
      const newLayers = [...layers];
      const [removed] = newLayers.splice(dragIndex, 1);
      newLayers.splice(hoverIndex, 0, removed);
      // Update zIndex based on new order
      setLayers(newLayers.map((layer, index) => ({ ...layer, zIndex: index })));
    },
    [layers, setLayers],
  );

  const toggleLayerVisibility = useCallback(
    (id: string) => {
      setLayers(layers.map((layer) => (layer.id === id ? { ...layer, isVisible: !layer.isVisible } : layer)));
    },
    [layers, setLayers],
  );

  const toggleLayerLock = useCallback(
    (id: string) => {
      setLayers(layers.map((layer) => (layer.id === id ? { ...layer, isLocked: !layer.isLocked } : layer)));
    },
    [layers, setLayers],
  );

  const getLayerById = useCallback(
    (id: string) => {
      return layers.find((layer) => layer.id === id);
    },
    [layers],
  );

  // ===== 컴포넌트 관리 함수 =====

  const addComponentToLayer = useCallback(
    (layerId: string, component: ComponentData) => {
      setLayers(
        layers.map((layer) => {
          if (layer.id === layerId) {
            return {
              ...layer,
              components: [...layer.components, component],
            };
          }
          return layer;
        }),
      );
    },
    [layers, setLayers],
  );

  const removeComponentFromLayer = useCallback(
    (layerId: string, componentId: string) => {
      setLayers(
        layers.map((layer) => {
          if (layer.id === layerId) {
            return {
              ...layer,
              components: layer.components.filter((c) => c.id !== componentId),
            };
          }
          return layer;
        }),
      );
    },
    [layers, setLayers],
  );

  const updateComponentInLayer = useCallback(
    (layerId: string, componentId: string, updates: Partial<ComponentData>) => {
      setLayers(
        layers.map((layer) => {
          if (layer.id === layerId) {
            return {
              ...layer,
              components: layer.components.map((c) =>
                c.id === componentId ? ({ ...c, ...updates } as ComponentData) : c,
              ),
            };
          }
          return layer;
        }),
      );
    },
    [layers, setLayers],
  );

  const moveComponentToLayer = useCallback(
    (componentId: string, fromLayerId: string, toLayerId: string) => {
      if (fromLayerId === toLayerId) return;

      const fromLayer = layers.find((l) => l.id === fromLayerId);
      const component = fromLayer?.components.find((c) => c.id === componentId);

      if (!component) return;

      setLayers(
        layers.map((layer) => {
          if (layer.id === fromLayerId) {
            return {
              ...layer,
              components: layer.components.filter((c) => c.id !== componentId),
            };
          }
          if (layer.id === toLayerId) {
            return {
              ...layer,
              components: [...layer.components, component],
            };
          }
          return layer;
        }),
      );
    },
    [layers, setLayers],
  );

  // ===== 컴포넌트 조회 함수 =====

  const getAllComponents = useCallback((): ComponentData[] => {
    return layers.flatMap((layer) => layer.components);
  }, [layers]);

  const getComponentById = useCallback(
    (componentId: string): { component: ComponentData; layerId: string } | null => {
      for (const layer of layers) {
        const component = layer.components.find((c) => c.id === componentId);
        if (component) {
          return { component, layerId: layer.id };
        }
      }
      return null;
    },
    [layers],
  );

  const getComponentsInActiveLayer = useCallback((): ComponentData[] => {
    const layer = layers.find((l) => l.id === activeLayerId);
    return layer?.components || [];
  }, [layers, activeLayerId]);

  // ===== 런타임 레이어 가시성 관리 =====

  const showLayer = useCallback((layerId: string) => {
    setRuntimeVisibleLayers((prev) => [...new Set([...prev, layerId])]);
  }, []);

  const hideLayer = useCallback((layerId: string) => {
    setRuntimeVisibleLayers((prev) => prev.filter((id) => id !== layerId));
  }, []);

  const toggleLayerRuntime = useCallback((layerId: string) => {
    setRuntimeVisibleLayers((prev) =>
      prev.includes(layerId) ? prev.filter((id) => id !== layerId) : [...prev, layerId],
    );
  }, []);

  return (
    <LayerContext.Provider
      value={{
        // 레이어 상태
        layers,
        activeLayerId,
        activeLayer,

        // 레이어 관리
        setLayers,
        setActiveLayerId,
        addLayer,
        removeLayer,
        updateLayer,
        moveLayer,
        toggleLayerVisibility,
        toggleLayerLock,
        getLayerById,

        // 컴포넌트 관리
        addComponentToLayer,
        removeComponentFromLayer,
        updateComponentInLayer,
        moveComponentToLayer,

        // 컴포넌트 조회
        getAllComponents,
        getComponentById,
        getComponentsInActiveLayer,

        // 런타임 가시성
        runtimeVisibleLayers,
        setRuntimeVisibleLayers,
        showLayer,
        hideLayer,
        toggleLayerRuntime,
      }}
    >
      {children}
    </LayerContext.Provider>
  );
};
