import { defineStore } from 'pinia';
import { v4 as uuidv4 } from 'uuid';
import { useVariableStore } from './variableStore';

export const useProcessBuilderStore = defineStore('processBuilder', {
  state: () => ({
    processes: [], // Only populated from database via fetchProcesses()
    currentProcess: null,
    selectedNodeId: null,
    selectedEdgeId: null,
    history: [],
    historyIndex: -1,
    unsavedChanges: false,
    lastChangeDescription: '',
    isModifyingNodes: false, // Flag to prevent interference during node operations
    // Validation state
    validationResults: new Map(),
    validationSummary: {
      totalIssues: 0,
      errors: 0,
      warnings: 0,
      infos: 0,
      isValid: true
    },
    overallValidationStatus: 'valid', // 'valid', 'warning', 'error'
    lastValidationTime: null,
    validationEnabled: true
  }),

  getters: {
    /**
     * Get the current process object
     */
    process: (state) => {
      return state.currentProcess;
    },

    /**
     * Get the selected node
     */
    selectedNode: (state) => {
      if (!state.currentProcess || !state.selectedNodeId) return null;
      return state.currentProcess.nodes.find(node => node.id === state.selectedNodeId);
    },

    /**
     * Get the selected edge
     */
    selectedEdge: (state) => {
      if (!state.currentProcess || !state.selectedEdgeId) return null;
      return state.currentProcess.edges.find(edge => edge.id === state.selectedEdgeId);
    },

    /**
     * Check if there are unsaved changes
     */
    hasUnsavedChanges: (state) => {
      return state.unsavedChanges;
    },

    /**
     * Check if undo is available
     */
    canUndo: (state) => {
      return state.historyIndex > 0;
    },

    /**
     * Check if redo is available
     */
    canRedo: (state) => {
      return state.historyIndex < state.history.length - 1;
    },

    /**
     * Get validation results for a specific node
     */
    getNodeValidation: (state) => (nodeId) => {
      return state.validationResults.get(nodeId) || [];
    },

    /**
     * Check if a node has validation issues
     */
    hasValidationIssues: (state) => (nodeId) => {
      const issues = state.validationResults.get(nodeId);
      return issues && issues.length > 0;
    },

    /**
     * Get validation icon for a node
     */
    getValidationIcon: (state) => (nodeId) => {
      const issues = state.validationResults.get(nodeId);
      if (!issues || issues.length === 0) return null;

      const hasError = issues.some(issue => issue.severity === 'error');
      const hasWarning = issues.some(issue => issue.severity === 'warning');

      if (hasError) return 'material-symbols:error';
      if (hasWarning) return 'material-symbols:warning';
      return 'material-symbols:info';
    },

    /**
     * Get validation tooltip for a node
     */
    getValidationTooltip: (state) => (nodeId) => {
      const issues = state.validationResults.get(nodeId);
      if (!issues || issues.length === 0) return null;

      const lines = issues.map(issue => `• ${issue.message}`);
      return lines.join('\n');
    }
  },

  actions: {
    /**
     * Create a new process
     */
    async createProcess(name, description = '') {
      try {
        const processData = {
          processName: name,
          processDescription: description,
          nodes: [],
          edges: [],
          viewport: { x: 0, y: 0, zoom: 1 },
          variables: {},
          settings: {},
          permissions: {},
          createdBy: 1 // TODO: Get from auth store
        };

        const response = await $fetch('/api/process/create', {
          method: 'POST',
          body: processData
        });

        if (response.success) {
          const process = {
            id: response.process.processUUID,
            name: response.process.processName,
            description: response.process.processDescription,
            nodes: response.process.processDefinition.nodes || [],
            edges: response.process.processDefinition.edges || [],
            variables: response.process.processVariables || {},
            settings: response.process.processSettings || {},
            permissions: response.process.processPermissions || {},
            createdAt: response.process.processCreatedDate,
            updatedAt: response.process.processModifiedDate
          };

          // Set as current process but DON'T add to processes array
          // The processes array should only be populated from fetchProcesses()
          this.currentProcess = process;
          this.unsavedChanges = false;

          // Clear any existing variables
          useVariableStore().clearProcessVariables();

          return process;
        } else {
          throw new Error(response.error || 'Failed to create process');
        }
      } catch (error) {
        console.error('Error creating process:', error);
        throw error;
      }
    },

    /**
     * Load a process
     */
    async loadProcess(processId) {
      try {
        const response = await $fetch(`/api/process/${processId}`);
        
        if (response.success) {
          const apiProcess = response.process;
          const definition = apiProcess.processDefinition;
          
          let nodes = definition.nodes || [];
          let edges = definition.edges || [];
          
          // If nodes array is empty but edges contain node data, extract nodes from edges
          if (nodes.length === 0 && edges.length > 0) {
            const nodeMap = new Map();
            
            // First try to extract unique nodes from edge sourceNode and targetNode if they exist
            edges.forEach(edge => {
              if (edge.sourceNode) {
                nodeMap.set(edge.sourceNode.id, {
                  id: edge.sourceNode.id,
                  type: edge.sourceNode.type,
                  label: edge.sourceNode.data?.label || edge.sourceNode.label,
                  position: edge.sourceNode.position,
                  data: edge.sourceNode.data || {}
                });
              }
              
              if (edge.targetNode) {
                nodeMap.set(edge.targetNode.id, {
                  id: edge.targetNode.id,
                  type: edge.targetNode.type,
                  label: edge.targetNode.data?.label || edge.targetNode.label,
                  position: edge.targetNode.position,
                  data: edge.targetNode.data || {}
                });
              }
            });
            
            // If no nodes were extracted from embedded data, create placeholder nodes from edge references
            if (nodeMap.size === 0) {
              const nodeIds = new Set();
              edges.forEach(edge => {
                if (edge.source) nodeIds.add(edge.source);
                if (edge.target) nodeIds.add(edge.target);
              });
              
              let nodePosition = { x: 100, y: 100 };
              const spacing = 200;
              
              nodeIds.forEach((nodeId, index) => {
                // Determine node type from ID prefix
                let nodeType = 'task'; // default
                let label = nodeId;
                let icon = 'schedule';
                
                if (nodeId.includes('start-')) {
                  nodeType = 'start';
                  label = 'Start Point';
                  icon = 'play-circle-rounded';
                } else if (nodeId.includes('end-')) {
                  nodeType = 'end';
                  label = 'End Point';
                  icon = 'stop-circle';
                } else if (nodeId.includes('form-')) {
                  nodeType = 'form';
                  label = 'Form';
                  icon = 'description';
                } else if (nodeId.includes('api-')) {
                  nodeType = 'api';
                  label = 'API Call';
                  icon = 'api';
                } else if (nodeId.includes('gateway-')) {
                  nodeType = 'gateway';
                  label = 'Decision Point';
                  icon = 'call-split';
                } else if (nodeId.includes('script-')) {
                  nodeType = 'script';
                  label = 'Script';
                  icon = 'code';
                }
                
                nodeMap.set(nodeId, {
                  id: nodeId,
                  type: nodeType,
                  label: label,
                  position: {
                    x: nodePosition.x + (index % 3) * spacing,
                    y: nodePosition.y + Math.floor(index / 3) * spacing
                  },
                  data: {
                    label: label,
                    description: `Recovered ${nodeType} node`,
                    icon: icon
                  }
                });
              });
              
              console.warn('Process had edges but no nodes. Created placeholder nodes from edge references:', Array.from(nodeIds));
            }
            
            // Convert to array
            nodes = Array.from(nodeMap.values());
            
            // Clean up edges to remove embedded node data (Vue Flow doesn't need it)
            edges = edges.map(edge => ({
              id: edge.id,
              source: edge.source,
              target: edge.target,
              label: edge.label || '',
              type: edge.type || 'smoothstep',
              animated: edge.animated !== undefined ? edge.animated : true,
              data: edge.data || {}
            }));
          }
          
          const process = {
            id: apiProcess.processUUID,
            name: apiProcess.processName,
            description: apiProcess.processDescription,
            nodes: nodes,
            edges: edges,
            viewport: definition.viewport || { x: 0, y: 0, zoom: 1 },
            variables: apiProcess.processVariables || {},
            settings: apiProcess.processSettings || {},
            permissions: apiProcess.processPermissions || {},
            createdAt: apiProcess.processCreatedDate,
            updatedAt: apiProcess.processModifiedDate
          };

          this.currentProcess = process;
          
          // Variables are already loaded in process.variables, no need to sync with variable store
          
          this.unsavedChanges = false;
          return { success: true, process };
        } else {
          const errorMessage = response.error || 'Failed to load process';
          console.error('Load process failed:', errorMessage);
          return { success: false, error: errorMessage };
        }
      } catch (error) {
        const errorMessage = error.data?.error || error.message || 'Network error occurred';
        console.error('Error loading process:', errorMessage);
        return { success: false, error: errorMessage };
      }
    },

    /**
     * Set the current process from the processes list
     */
    setCurrentProcess(processId) {
      const process = this.processes.find(p => p.id === processId);
      if (process) {
        this.currentProcess = JSON.parse(JSON.stringify(process)); // Deep clone
        this.selectedNodeId = null;
        this.selectedEdgeId = null;
        this.clearHistory();
        this.unsavedChanges = false;
      }
    },

    /**
     * Update the current process with new data
     */
    updateCurrentProcess(processUpdates) {
      if (!this.currentProcess) return;

      this.currentProcess = {
        ...this.currentProcess,
        ...processUpdates,
        updatedAt: new Date().toISOString()
      };
      
      this.unsavedChanges = true;
      this.saveToHistory('Update process settings');
    },

    /**
     * Save the current process
     */
    async saveProcess() {
      if (!this.currentProcess) return false;

      try {
        // Get variables from the current process, not from variable store
        const processVariables = this.currentProcess.variables || {};
        
        // Check if we need to capture Vue Flow state (when Vue Flow is available)
        let flowState = null;
        
        // Try to get the Vue Flow state from the canvas component
        // This will be set by the main process builder page when saving
        if (this.currentProcess.flowState) {
          flowState = this.currentProcess.flowState;
          console.log('💾 Using captured Vue Flow state for save:', {
            nodes: flowState.nodes?.length || 0,
            edges: flowState.edges?.length || 0,
            viewport: flowState.viewport
          });
        } else {
          console.log('💾 No Vue Flow state captured, using store data');
        }
        
        const processData = {
          processName: this.currentProcess.name,
          processDescription: this.currentProcess.description,
          // Use Vue Flow state if available, otherwise fallback to store data
          nodes: flowState?.nodes || this.currentProcess.nodes,
          edges: flowState?.edges || this.currentProcess.edges,
          viewport: flowState?.viewport || this.currentProcess.viewport || { x: 0, y: 0, zoom: 1 },
          variables: processVariables,
          settings: this.currentProcess.settings || {},
          permissions: this.currentProcess.permissions || {}
          // Note: processStatus is intentionally NOT included here to preserve current status
          // Status changes should only happen through explicit publish/unpublish actions
        };

        // Debug logging to see what we're actually sending
        console.log('💾 Saving process data:', {
          processId: this.currentProcess.id,
          nodeCount: processData.nodes.length,
          edgeCount: processData.edges.length,
          variableCount: Object.keys(processVariables).length,
          viewport: processData.viewport,
          nodes: processData.nodes.map(n => ({ id: n.id, type: n.type, label: n.label, position: n.position })),
          edges: processData.edges.map(e => ({ id: e.id, source: e.source, target: e.target }))
        });

        const response = await $fetch(`/api/process/${this.currentProcess.id}`, {
          method: 'PUT',
          body: processData
        });

        if (response.success) {
          // Update local state with server response
          const apiProcess = response.process;
          this.currentProcess.updatedAt = apiProcess.processModifiedDate;
          
          // Clear the temporary flowState after successful save
          delete this.currentProcess.flowState;
          
          // Update in processes array if it exists there
          const index = this.processes.findIndex(p => p.id === this.currentProcess.id);
          if (index !== -1) {
            this.processes[index] = { ...this.currentProcess };
          }

          this.unsavedChanges = false;
          return true;
        } else {
          throw new Error(response.error || 'Failed to save process');
        }
      } catch (error) {
        console.error('Error saving process:', error);
        return false;
      }
    },

    /**
     * Set Vue Flow state for saving
     */
    setFlowStateForSave(flowState) {
      if (this.currentProcess && flowState) {
        this.currentProcess.flowState = flowState;
        console.log('📊 Vue Flow state captured for save:', {
          nodes: flowState.nodes?.length || 0,
          edges: flowState.edges?.length || 0,
          viewport: flowState.viewport
        });
      }
    },

    /**
     * Clean flow data to remove Vue Flow internal properties
     */
    cleanFlowData(flowData) {
      if (!flowData) return { nodes: [], edges: [], viewport: { x: 0, y: 0, zoom: 1 } };
      
      // Clean nodes - keep only essential properties
      const cleanNodes = (flowData.nodes || []).map(node => ({
        id: node.id,
        type: node.type,
        label: node.label || node.data?.label || '',
        position: node.position || { x: 0, y: 0 },
        data: {
          label: node.data?.label || node.label || '',
          description: node.data?.description || '',
          // Include other essential data properties but exclude Vue Flow internals
          ...(node.data && typeof node.data === 'object' ? 
            Object.fromEntries(
              Object.entries(node.data).filter(([key]) => 
                !['events', 'dimensions', 'handleBounds', 'computedPosition'].includes(key)
              )
            ) : {}
          )
        }
      }));
      
      // Clean edges - keep only essential properties
      const cleanEdges = (flowData.edges || []).map(edge => ({
        id: edge.id,
        source: edge.source,
        target: edge.target,
        sourceHandle: edge.sourceHandle,
        targetHandle: edge.targetHandle,
        label: edge.label || '',
        type: edge.type || 'smoothstep',
        animated: edge.animated !== undefined ? edge.animated : true,
        data: edge.data && typeof edge.data === 'object' ? { ...edge.data } : {}
        // Exclude: sourceNode, targetNode, sourceX, sourceY, targetX, targetY, events
      }));
      
      // Clean viewport
      const cleanViewport = {
        x: flowData.viewport?.x || 0,
        y: flowData.viewport?.y || 0,
        zoom: flowData.viewport?.zoom || 1
      };
    
      return {
        nodes: cleanNodes,
        edges: cleanEdges,
        viewport: cleanViewport
      };
    },

    /**
     * Delete a process
     */
    async deleteProcess(processId) {
      try {
        const response = await $fetch(`/api/process/${processId}`, {
          method: 'DELETE'
        });

        if (response.success) {
          // Remove from local processes array (since we're filtering out deleted ones)
          const index = this.processes.findIndex(p => p.id === processId);
          if (index !== -1) {
            this.processes.splice(index, 1);
          }
          
          // Clear current process if it's the one being deleted
          if (this.currentProcess && this.currentProcess.id === processId) {
            this.currentProcess = null;
            this.selectedNodeId = null;
            this.selectedEdgeId = null;
            this.clearHistory();
          }
          
          return true;
        } else {
          throw new Error(response.error || 'Failed to delete process');
        }
      } catch (error) {
        console.error('Error deleting process:', error);
        return false;
      }
    },

    /**
     * Restore a deleted process
     */
    async restoreProcess(processId) {
      try {
        const response = await $fetch(`/api/process/${processId}/restore`, {
          method: 'POST'
        });

        if (response.success) {
          // Refresh the processes list to reflect the change
          // Don't modify local array directly since status filtering might be complex
          return true;
        } else {
          throw new Error(response.error || 'Failed to restore process');
        }
      } catch (error) {
        console.error('Error restoring process:', error);
        throw error;
      }
    },

    /**
     * Fetch all processes from database
     */
    async fetchProcesses(options = {}) {
      try {
        const queryParams = new URLSearchParams();
        
        if (options.page) queryParams.append('page', options.page);
        if (options.limit) queryParams.append('limit', options.limit);
        if (options.status) queryParams.append('status', options.status);
        if (options.category) queryParams.append('category', options.category);
        if (options.search) queryParams.append('search', options.search);
        if (options.isTemplate !== undefined) queryParams.append('isTemplate', options.isTemplate);
        if (options.sortBy) queryParams.append('sortBy', options.sortBy);
        if (options.sortOrder) queryParams.append('sortOrder', options.sortOrder);

        const url = `/api/process${queryParams.toString() ? '?' + queryParams.toString() : ''}`;
        const response = await $fetch(url);

        if (response.success) {
          // Replace the entire processes array with fresh data from database
          this.processes = response.data.processes.map(apiProcess => ({
            id: apiProcess.processUUID,
            name: apiProcess.processName,
            description: apiProcess.processDescription,
            category: apiProcess.processCategory,
            priority: apiProcess.processPriority,
            owner: apiProcess.processOwner,
            status: apiProcess.processStatus,
            isTemplate: apiProcess.isTemplate,
            templateCategory: apiProcess.templateCategory,
            createdAt: apiProcess.processCreatedDate,
            updatedAt: apiProcess.processModifiedDate,
            creator: apiProcess.creator
          }));
          
          return response.data;
        } else {
          throw new Error(response.error || 'Failed to fetch processes');
        }
      } catch (error) {
        console.error('Error fetching processes:', error);
        throw error;
      }
    },

    /**
     * Publish a process
     */
    async publishProcess(processId) {
      try {
        const response = await $fetch(`/api/process/${processId}/publish`, {
          method: 'POST'
        });

        if (response.success) {
          // Update local state if process exists in the array
          const process = this.processes.find(p => p.id === processId);
          if (process) {
            process.status = 'published';
            process.updatedAt = response.process.processModifiedDate;
          }
          
          // Update current process if it's the same one
          if (this.currentProcess && this.currentProcess.id === processId) {
            this.currentProcess.status = 'published';
            this.currentProcess.updatedAt = response.process.processModifiedDate;
          }
          
          return true;
        } else {
          throw new Error(response.error || 'Failed to publish process');
        }
      } catch (error) {
        console.error('Error publishing process:', error);
        throw error;
      }
    },

    /**
     * Unpublish a process (change status from published to draft)
     */
    async unpublishProcess(processId) {
      try {
        const response = await $fetch(`/api/process/${processId}/unpublish`, {
          method: 'POST'
        });

        if (response.success) {
          // Update local state if process exists in the array
          const process = this.processes.find(p => p.id === processId);
          if (process) {
            process.status = 'draft';
            process.updatedAt = response.process.processModifiedDate;
          }
          
          // Update current process if it's the same one
          if (this.currentProcess && this.currentProcess.id === processId) {
            this.currentProcess.status = 'draft';
            this.currentProcess.updatedAt = response.process.processModifiedDate;
          }
          
          return true;
        } else {
          throw new Error(response.error || 'Failed to unpublish process');
        }
      } catch (error) {
        console.error('Error unpublishing process:', error);
        throw error;
      }
    },

    /**
     * Duplicate a process
     */
    async duplicateProcess(processId, newName = null, asTemplate = false) {
      try {
        const response = await $fetch(`/api/process/${processId}/duplicate`, {
          method: 'POST',
          body: {
            newName,
            asTemplate,
            createdBy: 1 // TODO: Get from auth store
          }
        });

        if (response.success) {
          const apiProcess = response.process;
          const newProcess = {
            id: apiProcess.processUUID,
            name: apiProcess.processName,
            description: apiProcess.processDescription,
            category: apiProcess.processCategory,
            priority: apiProcess.processPriority,
            owner: apiProcess.processOwner,
            status: apiProcess.processStatus,
            isTemplate: apiProcess.isTemplate,
            templateCategory: apiProcess.templateCategory,
            createdAt: apiProcess.processCreatedDate,
            updatedAt: apiProcess.processModifiedDate,
            creator: apiProcess.creator
          };

          // DON'T add to processes array - let fetchProcesses() handle that
          // The manage page should call fetchProcesses() after duplication
          return newProcess;
        } else {
          throw new Error(response.error || 'Failed to duplicate process');
        }
      } catch (error) {
        console.error('Error duplicating process:', error);
        throw error;
      }
    },

    /**
     * Clear the processes list (useful when switching contexts)
     */
    clearProcesses() {
      this.processes = [];
    },

    /**
     * Clear the current process (useful when starting fresh)
     */
    clearCurrentProcess() {
      this.currentProcess = null;
      this.selectedNodeId = null;
      this.selectedEdgeId = null;
      this.clearHistory();
      this.unsavedChanges = false;
    },

    /**
     * Add a node to the current process
     */
    addNode(node) {
      if (!this.currentProcess) return;

      // Check if node already exists to prevent duplicates
      const existingNode = this.currentProcess.nodes.find(n => n.id === node.id);
      if (existingNode) {
        console.warn('Node already exists in store:', node.id);
        return existingNode;
      }

      // Set flag to prevent interference during node addition
      this.isModifyingNodes = true;

      try {
        // Create a new node with proper data structure
        const newNode = {
          id: node.id || uuidv4(),
          type: node.type,
          label: node.label || node.data?.label || '',
          position: node.position || { x: 100, y: 100 },
          data: {
            ...node.data,
            label: node.data?.label || node.label || '',
            // Ensure shape is set for new nodes
            shape: node.data?.shape || (node.type === 'gateway' ? 'diamond' : 'rectangle'),
            // Ensure default colors are set for new nodes
            backgroundColor: node.data?.backgroundColor || '#ffffff',
            borderColor: node.data?.borderColor || '#000000'
          }
        };

        // Create a deep copy to avoid reference issues
        const nodeCopy = JSON.parse(JSON.stringify(newNode));

        // Add to current process nodes array using push to avoid creating new array reference
        // This prevents triggering the watch that monitors currentProcess changes
        this.currentProcess.nodes.push(nodeCopy);
        
        // Update selection
        this.selectedNodeId = nodeCopy.id;
        
        // Save to history
        this.saveToHistory('Add node');
        this.unsavedChanges = true;

        console.log('📝 Store: Added node', nodeCopy.id, 'Total nodes:', this.currentProcess.nodes.length);

        return nodeCopy;
      } finally {
        // Reset flag after operation completes
        this.isModifyingNodes = false;
      }
    },

    /**
     * Update a node in the current process
     */
    updateNode(nodeId, updates) {
      if (!this.currentProcess) return;

      const node = this.currentProcess.nodes.find(n => n.id === nodeId);
      if (node) {
        Object.assign(node, updates);
        this.saveToHistory('Update node');
        this.unsavedChanges = true;
      }
    },

    /**
     * Delete a node from the current process
     */
    deleteNode(nodeId) {
      if (!this.currentProcess) return;

      // Set flag to prevent interference during node deletion
      this.isModifyingNodes = true;

      try {
        // Find the node index
        const index = this.currentProcess.nodes.findIndex(n => n.id === nodeId);
        if (index !== -1) {
          // Remove the node using splice to avoid creating new array reference
          this.currentProcess.nodes.splice(index, 1);
          
          // Remove any edges connected to this node
          const edgesToRemove = this.currentProcess.edges.filter(
            edge => edge.source === nodeId || edge.target === nodeId
          );
          
          edgesToRemove.forEach(edge => {
            const edgeIndex = this.currentProcess.edges.findIndex(e => e.id === edge.id);
            if (edgeIndex !== -1) {
              this.currentProcess.edges.splice(edgeIndex, 1);
            }
          });

          // Clear selection if the deleted node was selected
          if (this.selectedNodeId === nodeId) {
            this.selectedNodeId = null;
          }

          this.saveToHistory('Delete node');
          this.unsavedChanges = true;
          
          console.log('🗑️ Store: Deleted node', nodeId, 'Total nodes:', this.currentProcess.nodes.length);
          
          return true; // Return success
        }
        
        return false; // Return failure
      } finally {
        // Reset flag after operation completes
        this.isModifyingNodes = false;
      }
    },

    /**
     * Add an edge to the current process
     */
    addEdge(edge) {
      if (!this.currentProcess) return;

      // Set flag to prevent interference during edge addition
      this.isModifyingNodes = true;

      try {
        const newEdge = {
          id: edge.id || `${edge.source}-${edge.target}`,
          source: edge.source,
          target: edge.target,
          label: edge.label || '',
          type: edge.type || 'default',
          animated: edge.animated !== undefined ? edge.animated : true,
          data: edge.data || {}
        };

        // Use push to avoid creating new array reference
        this.currentProcess.edges.push(newEdge);
        this.selectedEdgeId = newEdge.id;
        this.saveToHistory('Add edge');
        this.unsavedChanges = true;

        console.log('🔗 Store: Added edge', newEdge.id, 'Total edges:', this.currentProcess.edges.length);

        return newEdge;
      } finally {
        // Reset flag after operation completes
        this.isModifyingNodes = false;
      }
    },

    /**
     * Update an edge in the current process
     */
    updateEdge(edgeIdOrObject, updates) {
      if (!this.currentProcess) return;

      // Handle different parameter formats
      let edgeId, edgeUpdates;
      
      if (typeof edgeIdOrObject === 'string') {
        // Called with (id, updates)
        edgeId = edgeIdOrObject;
        edgeUpdates = updates || {};
      } else if (typeof edgeIdOrObject === 'object') {
        // Called with an edge object
        edgeId = edgeIdOrObject.id;
        
        if (updates) {
          // Called with (edge, updates)
          edgeUpdates = updates;
        } else {
          // Called with just the edge object containing updates
          edgeUpdates = { ...edgeIdOrObject };
          delete edgeUpdates.id; // Don't update the ID
        }
      } else {
        return; // Invalid parameters
      }

      const edge = this.currentProcess.edges.find(e => e.id === edgeId);
      if (edge) {
        Object.assign(edge, edgeUpdates);
        this.saveToHistory('Update edge');
        this.unsavedChanges = true;
      }
    },

    /**
     * Delete an edge from the current process
     */
    deleteEdge(edgeId) {
      if (!this.currentProcess) return;

      const index = this.currentProcess.edges.findIndex(e => e.id === edgeId);
      if (index !== -1) {
        this.currentProcess.edges.splice(index, 1);
        
        if (this.selectedEdgeId === edgeId) {
          this.selectedEdgeId = null;
        }

        this.saveToHistory('Delete edge');
        this.unsavedChanges = true;
      }
    },

    /**
     * Update node positions after drag
     */
    updateNodePositions(nodePositions) {
      if (!this.currentProcess) return;

      Object.entries(nodePositions).forEach(([nodeId, position]) => {
        const node = this.currentProcess.nodes.find(n => n.id === nodeId);
        if (node) {
          node.position = position;
        }
      });

      this.saveToHistory('Move nodes');
      this.unsavedChanges = true;
    },

    /**
     * Select a node
     */
    selectNode(nodeId) {
      this.selectedNodeId = nodeId;
      this.selectedEdgeId = null;
    },

    /**
     * Select an edge
     */
    selectEdge(edgeId) {
      this.selectedEdgeId = edgeId;
      this.selectedNodeId = null;
    },

    /**
     * Clear selection
     */
    clearSelection() {
      this.selectedNodeId = null;
      this.selectedEdgeId = null;
    },

    /**
     * Save the current state to history
     */
    saveToHistory(actionName) {
      // Remove any future states if we're in the middle of the history
      if (this.historyIndex < this.history.length - 1) {
        this.history = this.history.slice(0, this.historyIndex + 1);
      }

      // Add current state to history
      this.history.push({
        state: JSON.parse(JSON.stringify(this.currentProcess)),
        action: actionName,
        timestamp: new Date().toISOString()
      });

      // Move history pointer
      this.historyIndex = this.history.length - 1;

      // Limit history size
      if (this.history.length > 50) {
        this.history.shift();
        this.historyIndex--;
      }
    },

    /**
     * Undo the last action
     */
    undo() {
      if (this.historyIndex > 0) {
        this.historyIndex--;
        this.currentProcess = JSON.parse(JSON.stringify(this.history[this.historyIndex].state));
        this.unsavedChanges = true;
      }
    },

    /**
     * Redo the last undone action
     */
    redo() {
      if (this.historyIndex < this.history.length - 1) {
        this.historyIndex++;
        this.currentProcess = JSON.parse(JSON.stringify(this.history[this.historyIndex].state));
        this.unsavedChanges = true;
      }
    },

    /**
     * Clear history
     */
    clearHistory() {
      this.history = [];
      this.historyIndex = -1;
    },

    /**
     * Get process version history
     */
    async getProcessHistory(processId) {
      try {
        const response = await $fetch(`/api/process/${processId}/history`);
        
        if (response.success) {
          return response.data;
        } else {
          throw new Error(response.error || 'Failed to get process history');
        }
      } catch (error) {
        console.error('Error getting process history:', error);
        throw error;
      }
    },

    /**
     * Get specific process version details
     */
    async getProcessVersion(processId, versionId) {
      try {
        const response = await $fetch(`/api/process/${processId}/version/${versionId}`);
        
        if (response.success) {
          return response.data;
        } else {
          throw new Error(response.error || 'Failed to get process version');
        }
      } catch (error) {
        console.error('Error getting process version:', error);
        throw error;
      }
    },

    /**
     * Restore process to a previous version
     */
    async restoreProcessVersion(processId, version) {
      try {
        const requestData = {
          historyId: version.historyID,
          versionNumber: version.versionNumber,
          restoredBy: 1 // TODO: Get from auth store
        };

        const response = await $fetch(`/api/process/${processId}/restore`, {
          method: 'POST',
          body: requestData
        });

        if (response.success) {
          // Update local state with restored process
          if (this.currentProcess && this.currentProcess.id === processId) {
            await this.loadProcess(processId);
          }
          
          return response;
        } else {
          throw new Error(response.error || 'Failed to restore process version');
        }
      } catch (error) {
        console.error('Error restoring process version:', error);
        throw error;
      }
    },

    /**
     * Load process version for preview (without changing current process)
     */
    async loadProcessVersionPreview(processId, versionId) {
      try {
        const response = await $fetch(`/api/process/${processId}/version/${versionId}`);
        
        if (response.success) {
          return response.data;
        } else {
          throw new Error(response.error || 'Failed to load process version preview');
        }
      } catch (error) {
        console.error('Error loading process version preview:', error);
        throw error;
      }
    },

    /**
     * Set change description for next save
     */
    setChangeDescription(description) {
      this.lastChangeDescription = description;
    },

    /**
     * Enhanced save process with change tracking
     */
    async saveProcessWithDescription(changeDescription = '') {
      if (!this.currentProcess) return false;

      try {
        const processData = {
          processName: this.currentProcess.name,
          processDescription: this.currentProcess.description,
          nodes: this.currentProcess.nodes,
          edges: this.currentProcess.edges,
          viewport: this.currentProcess.viewport || { x: 0, y: 0, zoom: 1 },
          variables: this.currentProcess.variables || {},
          settings: this.currentProcess.settings || {},
          permissions: this.currentProcess.permissions || {},
          changeDescription: changeDescription || this.lastChangeDescription,
          savedBy: 1 // TODO: Get from auth store
        };

        const response = await $fetch(`/api/process/${this.currentProcess.id}`, {
          method: 'PUT',
          body: processData
        });

        if (response.success) {
          // Update local state with server response
          const apiProcess = response.process;
          this.currentProcess.updatedAt = apiProcess.processModifiedDate;
          this.currentProcess.version = apiProcess.processVersion;
          
          // Update in processes array if it exists there
          const index = this.processes.findIndex(p => p.id === this.currentProcess.id);
          if (index !== -1) {
            this.processes[index] = { ...this.currentProcess };
          }

          this.unsavedChanges = false;
          this.lastChangeDescription = '';
          return response;
        } else {
          throw new Error(response.error || 'Failed to save process');
        }
      } catch (error) {
        console.error('Error saving process:', error);
        throw error;
      }
    },

    // Variable management methods
    /**
     * Add or update a variable in the current process
     */
    addProcessVariable(variable) {
      if (!this.currentProcess) return;
      
      if (!this.currentProcess.variables) {
        this.currentProcess.variables = {};
      }
      
      this.currentProcess.variables[variable.name] = {
        name: variable.name,
        type: variable.type || 'string',
        scope: variable.scope || 'global',
        value: variable.value,
        description: variable.description || '',
        captureFromUrl: variable.captureFromUrl || false,
        urlParameterName: variable.urlParameterName || ''
      };
      
      this.unsavedChanges = true;
    },

    /**
     * Update an existing variable in the current process
     */
    updateProcessVariable(name, updates) {
      if (!this.currentProcess || !this.currentProcess.variables || !this.currentProcess.variables[name]) {
        return;
      }
      
      this.currentProcess.variables[name] = {
        ...this.currentProcess.variables[name],
        ...updates
      };
      
      this.unsavedChanges = true;
    },

    /**
     * Delete a variable from the current process
     */
    deleteProcessVariable(name) {
      if (!this.currentProcess || !this.currentProcess.variables) {
        return;
      }
      
      delete this.currentProcess.variables[name];
      this.unsavedChanges = true;
    },

    /**
     * Get all variables from the current process
     */
    getProcessVariables() {
      if (!this.currentProcess || !this.currentProcess.variables) {
        return [];
      }
      
      return Object.values(this.currentProcess.variables);
    },

    /**
     * Get a specific variable from the current process
     */
    getProcessVariable(name) {
      if (!this.currentProcess || !this.currentProcess.variables) {
        return null;
      }
      
      return this.currentProcess.variables[name] || null;
    },

    /**
     * Update all references to a variable when its name changes
     * This ensures data integrity across all nodes that reference the variable
     */
    updateVariableReferences(oldVariableName, newVariableName) {
      if (!this.currentProcess || !this.currentProcess.nodes || oldVariableName === newVariableName) {
        return;
      }

      console.log(`Updating variable references from "${oldVariableName}" to "${newVariableName}"`);

      this.currentProcess.nodes.forEach(node => {
        if (!node.data) return;

        switch (node.type) {
          case 'api':
            // Update API node output and error variables
            if (node.data.outputVariable === oldVariableName) {
              node.data.outputVariable = newVariableName;
              console.log(`Updated API node ${node.id} outputVariable`);
            }
            if (node.data.errorVariable === oldVariableName) {
              node.data.errorVariable = newVariableName;
              console.log(`Updated API node ${node.id} errorVariable`);
            }
            break;

          case 'script':
            // Update script node output variables and error variable
            if (node.data.errorVariable === oldVariableName) {
              node.data.errorVariable = newVariableName;
              console.log(`Updated Script node ${node.id} errorVariable`);
            }
            if (node.data.outputVariables && Array.isArray(node.data.outputVariables)) {
              node.data.outputVariables.forEach(output => {
                if (output.name === oldVariableName) {
                  output.name = newVariableName;
                  console.log(`Updated Script node ${node.id} outputVariable`);
                }
              });
            }
            break;

          case 'form':
            // Update form node field mappings (both input and output mappings)
            if (node.data.inputMappings && Array.isArray(node.data.inputMappings)) {
              node.data.inputMappings.forEach(mapping => {
                if (mapping.processVariable === oldVariableName) {
                  mapping.processVariable = newVariableName;
                  console.log(`Updated Form node ${node.id} input mapping`);
                }
              });
            }
            if (node.data.outputMappings && Array.isArray(node.data.outputMappings)) {
              node.data.outputMappings.forEach(mapping => {
                if (mapping.processVariable === oldVariableName) {
                  mapping.processVariable = newVariableName;
                  console.log(`Updated Form node ${node.id} output mapping`);
                }
              });
            }
            if (node.data.fieldMappings && Array.isArray(node.data.fieldMappings)) {
              node.data.fieldMappings.forEach(mapping => {
                if (mapping.processVariable === oldVariableName) {
                  mapping.processVariable = newVariableName;
                  console.log(`Updated Form node ${node.id} field mapping`);
                }
              });
            }
            break;

          case 'businessRule':
            // Update business rule conditions (handle both ruleGroups and conditions structures)
            if (node.data.ruleGroups && Array.isArray(node.data.ruleGroups)) {
              node.data.ruleGroups.forEach(ruleGroup => {
                if (ruleGroup.conditions && Array.isArray(ruleGroup.conditions)) {
                  ruleGroup.conditions.forEach(condition => {
                    if (condition.variable === oldVariableName) {
                      condition.variable = newVariableName;
                      console.log(`Updated Business Rule node ${node.id} ruleGroup condition variable`);
                    }
                  });
                }
              });
            }
            if (node.data.conditions && Array.isArray(node.data.conditions)) {
              node.data.conditions.forEach(conditionGroup => {
                if (conditionGroup.conditions && Array.isArray(conditionGroup.conditions)) {
                  conditionGroup.conditions.forEach(condition => {
                    if (condition.variable === oldVariableName) {
                      condition.variable = newVariableName;
                      console.log(`Updated Business Rule node ${node.id} condition variable`);
                    }
                  });
                }
              });
            }
            break;

          case 'notification':
            // Update notification content that may contain variable placeholders
            if (node.data.subject) {
              const oldPlaceholder = `{${oldVariableName}}`;
              const newPlaceholder = `{${newVariableName}}`;
              if (node.data.subject.includes(oldPlaceholder)) {
                node.data.subject = node.data.subject.replace(new RegExp(`\\{${oldVariableName}\\}`, 'g'), newPlaceholder);
                console.log(`Updated Notification node ${node.id} subject`);
              }
            }
            if (node.data.content) {
              const oldPlaceholder = `{${oldVariableName}}`;
              const newPlaceholder = `{${newVariableName}}`;
              if (node.data.content.includes(oldPlaceholder)) {
                node.data.content = node.data.content.replace(new RegExp(`\\{${oldVariableName}\\}`, 'g'), newPlaceholder);
                console.log(`Updated Notification node ${node.id} content`);
              }
            }
            break;

          case 'gateway':
            // Update gateway conditions
            if (node.data.conditions && Array.isArray(node.data.conditions)) {
              node.data.conditions.forEach(conditionGroup => {
                if (conditionGroup.conditions && Array.isArray(conditionGroup.conditions)) {
                  conditionGroup.conditions.forEach(condition => {
                    if (condition.variable === oldVariableName) {
                      condition.variable = newVariableName;
                      console.log(`Updated Gateway node ${node.id} condition variable`);
                    }
                  });
                }
              });
            }
            break;

          default:
            // For any other node types, check if there are variable references in the data
            const nodeDataStr = JSON.stringify(node.data);
            if (nodeDataStr.includes(oldVariableName)) {
              console.log(`Warning: Node ${node.id} (type: ${node.type}) may contain references to variable "${oldVariableName}" that need manual review`);
            }
            break;
        }
      });

      this.unsavedChanges = true;
    },

    /**
     * Rename a variable and update all its references
     */
    renameProcessVariable(oldName, newName) {
      if (!this.currentProcess || !this.currentProcess.variables || oldName === newName) {
        return false;
      }

      // Check if new name already exists
      if (this.currentProcess.variables[newName]) {
        console.error(`Variable "${newName}" already exists`);
        return false;
      }

      // Get the variable data
      const variableData = this.currentProcess.variables[oldName];
      if (!variableData) {
        console.error(`Variable "${oldName}" not found`);
        return false;
      }

      // Update all references in nodes
      this.updateVariableReferences(oldName, newName);

      // Update the variable in the variables object
      delete this.currentProcess.variables[oldName];
      this.currentProcess.variables[newName] = {
        ...variableData,
        name: newName
      };

      // Force reactivity update by creating a new object reference
      this.currentProcess.variables = { ...this.currentProcess.variables };

      // Force update of the entire process to trigger reactivity in all components
      this.currentProcess = { ...this.currentProcess };

      console.log(`Successfully renamed variable from "${oldName}" to "${newName}"`);
      this.unsavedChanges = true;
      return true;
    },

    /**
     * Update validation results
     */
    updateValidationResults(validationResults, validationSummary, overallStatus) {
      this.validationResults = new Map(validationResults);
      this.validationSummary = { ...validationSummary };
      this.overallValidationStatus = overallStatus;
      this.lastValidationTime = new Date();
    },

    /**
     * Clear all validation results
     */
    clearValidationResults() {
      this.validationResults.clear();
      this.validationSummary = {
        totalIssues: 0,
        errors: 0,
        warnings: 0,
        infos: 0,
        isValid: true
      };
      this.overallValidationStatus = 'valid';
      this.lastValidationTime = null;
    },

    /**
     * Toggle validation on/off
     */
    toggleValidation() {
      this.validationEnabled = !this.validationEnabled;
      if (!this.validationEnabled) {
        this.clearValidationResults();
      }
    },

    /**
     * Set validation enabled state
     */
    setValidationEnabled(enabled) {
      this.validationEnabled = enabled;
      if (!enabled) {
        this.clearValidationResults();
      }
    }
  }
}); 