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>
  );
};
