import React, { createContext, useContext, useState, useCallback, useRef, useEffect } from 'react';
import { debounce } from 'lodash';
import { Node, Edge } from '@xyflow/react';

interface HistoryContextType {
  undo: () => void;
  redo: () => void;
  canUndo: boolean;
  canRedo: boolean;
  takeSnapshot: () => void;
}

const HistoryContext = createContext<HistoryContextType | undefined>(undefined);

export const useHistory = () => {
  const context = useContext(HistoryContext);
  if (!context) {
    throw new Error('useHistory must be used within a HistoryProvider');
  }
  return context;
};

interface HistoryProviderProps {
  children: React.ReactNode;
  initialNodes: Node[];
  initialEdges: Edge[];
  onHistoryChange: (nodes: Node[], edges: Edge[]) => void;
}

const HistoryProvider: React.FC<HistoryProviderProps> = ({
                                                           children,
                                                           initialNodes,
                                                           initialEdges,
                                                           onHistoryChange
                                                         }) => {
  // 历史记录状态
  const [history, setHistory] = useState<{ nodes: Node[]; edges: Edge[] }[]>([
    { nodes: initialNodes, edges: initialEdges }
  ]);
  const [step, setStep] = useState(0);

  // 当前状态的引用，避免重复添加相同状态
  const currentState = useRef({
    nodes: initialNodes,
    edges: initialEdges
  });

  // 检查两个状态是否相等
  const isSameState = useCallback((state1: { nodes: Node[]; edges: Edge[] }, state2: {
    nodes: Node[];
    edges: Edge[]
  }) => {
    // 只比较节点和边的关键属性，忽略拖动过程中的临时状态
    if (state1.nodes.length !== state2.nodes.length || state1.edges.length !== state2.edges.length) {
      return false;
    }

    // 比较节点
    for (let i = 0; i < state1.nodes.length; i++) {
      const node1 = state1.nodes[i];
      const node2 = state2.nodes[i];

      if (node1.id !== node2.id ||
        node1.type !== node2.type ||
        node1.position.x !== node2.position.x ||
        node1.position.y !== node2.position.y ||
        JSON.stringify(node1.data) !== JSON.stringify(node2.data)) {
        return false;
      }
    }

    // 比较边
    for (let i = 0; i < state1.edges.length; i++) {
      const edge1 = state1.edges[i];
      const edge2 = state2.edges[i];

      if (edge1.id !== edge2.id ||
        edge1.source !== edge2.source ||
        edge1.target !== edge2.target ||
        edge1.sourceHandle !== edge2.sourceHandle ||
        edge1.targetHandle !== edge2.targetHandle) {
        return false;
      }
    }

    return true;
  }, []);

  // 拍摄快照
  const takeSnapshot = useCallback(() => {
    // 获取当前状态
    const { nodes, edges } = currentState.current;

    // 如果当前状态与历史记录中的当前步骤相同，则不添加新快照
    const currentHistoryState = history[step];
    if (isSameState({ nodes, edges }, currentHistoryState)) {
      return;
    }

    // 删除当前步骤之后的所有历史记录
    const newHistory = history.slice(0, step + 1);

    // 添加新快照
    newHistory.push({
      nodes: nodes.map(node => ({ ...node })),
      edges: edges.map(edge => ({ ...edge }))
    });

    // 限制历史记录长度，防止内存泄漏
    const maxLength = 100;
    if (newHistory.length > maxLength) {
      newHistory.shift();
      setStep(prev => prev - 1);
    }

    setHistory(newHistory);
    setStep(newHistory.length - 1);
  }, [history, step, isSameState]);

  // 撤销操作
  const undo = useCallback(() => {
    if (step <= 0) return;

    const prevStep = step - 1;
    const { nodes, edges } = history[prevStep];

    currentState.current = { nodes, edges };
    setStep(prevStep);
    onHistoryChange([...nodes], [...edges]);
  }, [step, history, onHistoryChange]);

  // 重做操作
  const redo = useCallback(() => {
    if (step >= history.length - 1) return;

    const nextStep = step + 1;
    const { nodes, edges } = history[nextStep];

    currentState.current = { nodes, edges };
    setStep(nextStep);
    onHistoryChange([...nodes], [...edges]);
  }, [step, history, onHistoryChange]);

  // 更新当前状态的引用
  const updateCurrentState = useCallback((nodes: Node[], edges: Edge[]) => {
    currentState.current = { nodes, edges };
  }, []);

  // 监听 takeSnapshot 事件
  useEffect(() => {
    const handleTakeSnapshot = debounce((event: CustomEvent) => {
      const { nodes, edges } = event.detail;
      updateCurrentState(nodes, edges);
      takeSnapshot();
    }, 100) as EventListener;

    document.addEventListener('takeSnapshot', handleTakeSnapshot);
    return () => {
      document.removeEventListener('takeSnapshot', handleTakeSnapshot);
    };
  }, [takeSnapshot, updateCurrentState]);

  const value = {
    undo,
    redo,
    canUndo: step > 0,
    canRedo: step < history.length - 1,
    takeSnapshot
  };

  return (
    <HistoryContext.Provider value={value}>
      {children}
    </HistoryContext.Provider>
  );
};

export default HistoryProvider;