/**
 * 流程设计器状态管理
 */

import { create } from 'zustand';
import {
  ProcessNode,
  ProcessEdge,
  ProcessModel,
  ProcessSettings,
  ProcessNodeConfig,
  createDefaultProcessModel,
  generateNodeId,
  generateEdgeId,
} from './types';

interface ProcessDesignerState {
  // 流程数据
  nodes: ProcessNode[];
  edges: ProcessEdge[];
  settings: ProcessSettings;
  
  // 选中状态
  selectedNodeId: string | null;
  selectedEdgeId: string | null;
  
  // 编辑状态
  isDirty: boolean;
  
  // 历史记录
  history: Array<{ nodes: ProcessNode[]; edges: ProcessEdge[] }>;
  historyIndex: number;
}

interface ProcessDesignerActions {
  // 初始化
  initFromModel: (model: ProcessModel) => void;
  reset: () => void;
  
  // 节点操作
  addNode: (node: ProcessNode) => void;
  updateNode: (nodeId: string, updates: Partial<ProcessNode>) => void;
  updateNodeConfig: (nodeId: string, config: Partial<ProcessNodeConfig>) => void;
  removeNode: (nodeId: string) => void;
  moveNode: (nodeId: string, position: { x: number; y: number }) => void;
  
  // 连线操作
  addEdge: (edge: ProcessEdge) => void;
  updateEdge: (edgeId: string, updates: Partial<ProcessEdge>) => void;
  removeEdge: (edgeId: string) => void;
  
  // 选中操作
  selectNode: (nodeId: string | null) => void;
  selectEdge: (edgeId: string | null) => void;
  
  // 设置操作
  updateSettings: (settings: Partial<ProcessSettings>) => void;
  
  // 历史操作
  undo: () => void;
  redo: () => void;
  
  // 导出
  toProcessModel: () => ProcessModel;
  
  // 标记已保存
  markSaved: () => void;
}

const initialState: ProcessDesignerState = {
  nodes: [],
  edges: [],
  settings: {
    withdraw: {
      allowWithdraw: true,
      withdrawReason: true,
    },
    approverWithdraw: {
      enabled: true,
      timeLimit: 24,
      requireReason: true,
      notifyInitiator: true,
    },
    defaultPriority: 1,
    maxNodeExecutions: 10,
    maxTotalNodeExecutions: 100,
    maxReturnCount: 5,
  },
  selectedNodeId: null,
  selectedEdgeId: null,
  isDirty: false,
  history: [],
  historyIndex: -1,
};

export const useProcessDesignerStore = create<ProcessDesignerState & ProcessDesignerActions>(
  (set, get) => ({
    ...initialState,
    
    initFromModel: (model: ProcessModel) => {
      set({
        nodes: model.nodes,
        edges: model.edges,
        selectedNodeId: null,
        selectedEdgeId: null,
        isDirty: false,
        history: [{ nodes: model.nodes, edges: model.edges }],
        historyIndex: 0,
      });
    },
    
    reset: () => {
      const defaultModel = createDefaultProcessModel();
      set({
        ...initialState,
        nodes: defaultModel.nodes,
        edges: defaultModel.edges,
        history: [{ nodes: defaultModel.nodes, edges: defaultModel.edges }],
        historyIndex: 0,
      });
    },
    
    addNode: (node: ProcessNode) => {
      const { nodes, edges, historyIndex, history } = get();
      const newNodes = [...nodes, node];
      const newHistory = history.slice(0, historyIndex + 1);
      newHistory.push({ nodes: newNodes, edges });
      
      set({
        nodes: newNodes,
        isDirty: true,
        history: newHistory,
        historyIndex: newHistory.length - 1,
      });
    },
    
    updateNode: (nodeId: string, updates: Partial<ProcessNode>) => {
      const { nodes, edges, historyIndex, history } = get();
      const newNodes = nodes.map((n) =>
        n.id === nodeId ? { ...n, ...updates } : n
      );
      const newHistory = history.slice(0, historyIndex + 1);
      newHistory.push({ nodes: newNodes, edges });
      
      set({
        nodes: newNodes,
        isDirty: true,
        history: newHistory,
        historyIndex: newHistory.length - 1,
      });
    },
    
    updateNodeConfig: (nodeId: string, config: Partial<ProcessNodeConfig>) => {
      const { nodes, edges, historyIndex, history } = get();
      const newNodes = nodes.map((n) =>
        n.id === nodeId
          ? { ...n, config: { ...n.config, ...config } }
          : n
      );
      const newHistory = history.slice(0, historyIndex + 1);
      newHistory.push({ nodes: newNodes, edges });
      
      set({
        nodes: newNodes,
        isDirty: true,
        history: newHistory,
        historyIndex: newHistory.length - 1,
      });
    },
    
    removeNode: (nodeId: string) => {
      const { nodes, edges, historyIndex, history, selectedNodeId } = get();
      const newNodes = nodes.filter((n) => n.id !== nodeId);
      const newEdges = edges.filter(
        (e) => e.source !== nodeId && e.target !== nodeId
      );
      const newHistory = history.slice(0, historyIndex + 1);
      newHistory.push({ nodes: newNodes, edges: newEdges });
      
      set({
        nodes: newNodes,
        edges: newEdges,
        isDirty: true,
        history: newHistory,
        historyIndex: newHistory.length - 1,
        selectedNodeId: selectedNodeId === nodeId ? null : selectedNodeId,
      });
    },
    
    moveNode: (nodeId: string, position: { x: number; y: number }) => {
      const { nodes } = get();
      const newNodes = nodes.map((n) =>
        n.id === nodeId ? { ...n, position } : n
      );
      
      // 移动节点不记录到历史（太频繁）
      set({
        nodes: newNodes,
        isDirty: true,
      });
    },
    
    addEdge: (edge: ProcessEdge) => {
      const { nodes, edges, historyIndex, history } = get();
      
      // 检查是否已存在相同的连线
      const exists = edges.some(
        (e) => e.source === edge.source && e.target === edge.target
      );
      if (exists) return;
      
      const newEdges = [...edges, edge];
      const newHistory = history.slice(0, historyIndex + 1);
      newHistory.push({ nodes, edges: newEdges });
      
      set({
        edges: newEdges,
        isDirty: true,
        history: newHistory,
        historyIndex: newHistory.length - 1,
      });
    },
    
    updateEdge: (edgeId: string, updates: Partial<ProcessEdge>) => {
      const { nodes, edges, historyIndex, history } = get();
      const newEdges = edges.map((e) =>
        e.id === edgeId ? { ...e, ...updates } : e
      );
      const newHistory = history.slice(0, historyIndex + 1);
      newHistory.push({ nodes, edges: newEdges });
      
      set({
        edges: newEdges,
        isDirty: true,
        history: newHistory,
        historyIndex: newHistory.length - 1,
      });
    },
    
    removeEdge: (edgeId: string) => {
      const { nodes, edges, historyIndex, history, selectedEdgeId } = get();
      const newEdges = edges.filter((e) => e.id !== edgeId);
      const newHistory = history.slice(0, historyIndex + 1);
      newHistory.push({ nodes, edges: newEdges });
      
      set({
        edges: newEdges,
        isDirty: true,
        history: newHistory,
        historyIndex: newHistory.length - 1,
        selectedEdgeId: selectedEdgeId === edgeId ? null : selectedEdgeId,
      });
    },
    
    selectNode: (nodeId: string | null) => {
      set({
        selectedNodeId: nodeId,
        selectedEdgeId: null,
      });
    },
    
    selectEdge: (edgeId: string | null) => {
      set({
        selectedEdgeId: edgeId,
        selectedNodeId: null,
      });
    },
    
    updateSettings: (settings: Partial<ProcessSettings>) => {
      const { settings: currentSettings } = get();
      set({
        settings: { ...currentSettings, ...settings },
        isDirty: true,
      });
    },
    
    undo: () => {
      const { historyIndex, history } = get();
      if (historyIndex > 0) {
        const newIndex = historyIndex - 1;
        const snapshot = history[newIndex];
        set({
          nodes: snapshot.nodes,
          edges: snapshot.edges,
          historyIndex: newIndex,
          isDirty: true,
        });
      }
    },
    
    redo: () => {
      const { historyIndex, history } = get();
      if (historyIndex < history.length - 1) {
        const newIndex = historyIndex + 1;
        const snapshot = history[newIndex];
        set({
          nodes: snapshot.nodes,
          edges: snapshot.edges,
          historyIndex: newIndex,
          isDirty: true,
        });
      }
    },
    
    toProcessModel: () => {
      const { nodes, edges } = get();
      return { nodes, edges };
    },
    
    markSaved: () => {
      set({ isDirty: false });
    },
  })
);

// 辅助 hooks
export function useSelectedNode() {
  const { nodes, selectedNodeId } = useProcessDesignerStore();
  return nodes.find((n) => n.id === selectedNodeId) || null;
}

export function useSelectedEdge() {
  const { edges, selectedEdgeId } = useProcessDesignerStore();
  return edges.find((e) => e.id === selectedEdgeId) || null;
}

export function useCanUndo() {
  const { historyIndex } = useProcessDesignerStore();
  return historyIndex > 0;
}

export function useCanRedo() {
  const { historyIndex, history } = useProcessDesignerStore();
  return historyIndex < history.length - 1;
}
