/**
 * Custom hook for node and edge configuration management
 * Handles configuration changes, updates, and auto-layout functionality
 */

import { useCallback } from 'react';
import { useStore } from '../store/store';
import { autoLayout } from '../utils/modelUtils';
import { getEdgeType, getEdgeTypeWithCondition } from '../utils/edgeTypeUtils';

interface UseConfigurationProps {
  setHasUnsavedChanges: (value: boolean) => void;
}

export function useConfiguration({ setHasUnsavedChanges }: UseConfigurationProps) {
  const nodes = useStore(state => state.nodes);
  const edges = useStore(state => state.edges);
  const setNodes = useStore(state => state.setNodes);
  const setEdges = useStore(state => state.setEdges);
  const selectedNode = useStore(state => state.selectedNode);
  const setSelectedNode = useStore(state => state.setSelectedNode);
  const selectedEdge = useStore(state => state.selectedEdge);
  const setSelectedEdge = useStore(state => state.setSelectedEdge);

  // Configuration change handler - updates node configuration (primary callback)
  const onConfigurationChange = useCallback((nodeId: string, configuration: Record<string, any>) => {
    setNodes(prev => prev.map(node => 
      node.id === nodeId 
        ? { 
            ...node, 
            data: { 
              ...(node.data || {}), // Ensure data is never undefined
              // Store configuration in the configuration object
              configuration: { ...(node.data?.configuration || {}), ...configuration },
              // Also map _componentLabel to label for display
              ...(configuration._componentLabel ? { label: configuration._componentLabel } : {}),
              // Handle component locking directly on data object
              ...(configuration._componentLocked !== undefined ? { locked: configuration._componentLocked } : {})
            }
          }
        : node
    ));
    
    // Update selected node to reflect changes in property panel
    if (selectedNode?.id === nodeId) {
      setTimeout(() => {
        const updatedNode = nodes.find(n => n.id === nodeId);
        if (updatedNode) {
          setSelectedNode(updatedNode);
        }
      }, 10);
    }
    
    setHasUnsavedChanges(true);
  }, [setNodes, selectedNode, setSelectedNode, setHasUnsavedChanges, nodes]);

  // Edge configuration change handler
  const onEdgeConfigurationChange = useCallback((edgeId: string, configurationOrCallback: Record<string, any> | null | ((edge: any) => Record<string, any> | null)) => {
    setEdges(prev => prev.map(edge => {
      if (edge.id !== edgeId) return edge;
      
      // Handle callback pattern to get current state
      const configuration = typeof configurationOrCallback === 'function' 
        ? configurationOrCallback(edge)
        : configurationOrCallback;
      
      // Extract condition label from either _conditionLabel (special key) or conditionLabel
      const newConditionLabel = configuration?._conditionLabel ?? configuration?.conditionLabel;
      
      // Remove special keys that shouldn't be stored in conditionConfiguration
      const { _conditionLabel: _, conditionLabel: __, edgeLocked, ...restConfiguration } = configuration || {};
      
      const newData = { 
        ...edge.data, 
        // Store configuration in the conditionConfiguration object (excluding special keys)
        conditionConfiguration: configuration 
          ? { ...edge.data?.conditionConfiguration, ...restConfiguration } 
          : null,
        // Also map conditionLabel for data consistency
        ...(newConditionLabel !== undefined ? { conditionLabel: newConditionLabel } : {}),
        // Handle edge locking directly on data object
        ...(edgeLocked !== undefined ? { locked: edgeLocked } : {})
      };
      
      return { 
        ...edge, 
        // Update top-level label property for ReactFlow display
        ...(newConditionLabel !== undefined ? { label: newConditionLabel } : {}),
        // Update edge type based on content
        type: getEdgeTypeWithCondition(configuration ? 'has-config' : null, newData),
        data: newData
      };
    }));
    
    // Also update selectedEdge if it's the one being changed
    if (selectedEdge?.id === edgeId && setSelectedEdge) {
      setTimeout(() => {
        const updatedEdge = edges.find(e => e.id === edgeId);
        if (updatedEdge) {
          setSelectedEdge(updatedEdge);
        }
      }, 10);
    }
    
    setHasUnsavedChanges(true);
  }, [setEdges, selectedEdge, setSelectedEdge, edges, setHasUnsavedChanges]);

  // Node update handler (for broader updates than just config)
  const onNodeUpdate = useCallback((nodeId: string, newData: any) => {
    setNodes(prev => prev.map(node => 
      node.id === nodeId 
        ? { ...node, data: { ...node.data, ...newData } }
        : node
    ));
    setHasUnsavedChanges(true);
  }, [setNodes, setHasUnsavedChanges]);

  // Edge update handler (for broader updates than just config)
  const onEdgeUpdate = useCallback((edgeId: string, newData: any) => {
    setEdges(prev => prev.map(edge => 
      edge.id === edgeId 
        ? { 
            ...edge, 
            data: { ...edge.data, ...newData }, // Merge with existing data instead of replacing
            // Update edge type based on merged data
            type: getEdgeType({ ...edge.data, ...newData })
          }
        : edge
    ));
    setHasUnsavedChanges(true);
  }, [setEdges, setHasUnsavedChanges]);

  // Auto-layout handler
  const handleAutoLayout = useCallback(() => {
    const layoutedNodes = autoLayout(nodes, edges);
    if (layoutedNodes) {
      setNodes(layoutedNodes);
      setHasUnsavedChanges(true);
    }
  }, [nodes, edges, setNodes, setHasUnsavedChanges]);

  return {
    onConfigurationChange,
    onEdgeConfigurationChange,
    onNodeUpdate,
    onEdgeUpdate,
    handleAutoLayout
  };
}