/**
 * Custom hook for model data loading and management
 * Handles parsing, loading, and initial setup of model data from Drupal
 */

import { useEffect, useMemo } from 'react';
import { useStore } from '../store/store';
import { parseModelData } from '../utils/modelUtils';
import { validateModelDataShape } from '../utils/validation';
import { VIEWPORT, TIMING } from '../constants/dimensions';
import { t } from '../utils/translation';
import { getComponentLabel, setActiveComponentLabels } from '../utils/componentUtils';
import type { Settings } from '../types/settings';

interface UseModelDataLoaderProps {
  settings: Settings;
  setViewportTarget: (target: any) => void;
}

// ============ Extracted Helper Functions ============

function createGatewayComponent() {
  return {
    type: 'gateway',
    category: t('Others'),
    provider: 'modeler',
    label: getComponentLabel('gateway'),
    plugin: 'gateway',
    description: t('Gateway for conditional branching and decision making'),
  };
}

/** Ensure the gateway component exists in the components array */
function ensureGatewayComponent(components: any[]): any[] {
  const hasGateway = components.some(comp => comp.plugin === 'gateway');
  if (hasGateway) return components;
  return [...components, createGatewayComponent()];
}

/** Convert ownerComponents (keyed by category) to a flat component array */
function flattenOwnerComponents(ownerComponents: Record<string, any[]>): any[] {
  const allComponents: any[] = [];
  Object.keys(ownerComponents).forEach(category => {
    const categoryComponents = ownerComponents[category];
    if (Array.isArray(categoryComponents)) {
      categoryComponents.forEach(comp => {
        allComponents.push({ ...comp, category });
      });
    }
  });
  return allComponents;
}

/** Parse raw model JSON, validate, and merge with settings metadata */
function parseAndMergeModelData(
  rawJson: any,
  settings: Settings,
  source: string
): { modelData: any; nodes: any[]; edges: any[] } | null {
  try {
    const data = typeof rawJson === 'string' ? JSON.parse(rawJson) : rawJson;

    // Validate structural shape before parsing
    const warnings = validateModelDataShape(data);
    if (warnings.length > 0) {
      console.warn(`Model data validation warnings (${source}):`, warnings);
    }

    const parsedData = parseModelData(data);
    
    // Merge model data with modelId from settings and metadata from API
    const mergedModelData = {
      ...parsedData.modelData,
      id: settings.modeler?.modelId || parsedData.modelData?.id || '',
      metadata: {
        ...parsedData.modelData?.metadata,
        ...settings.modeler_api?.metadata,
      },
    };

    // Ensure all nodes have proper data structure
    const nodesWithData = (parsedData.nodes || []).map(node => ({
      ...node,
      data: node.data || {}
    }));

    return {
      modelData: mergedModelData,
      nodes: nodesWithData,
      edges: parsedData.edges || [],
    };
  } catch (error) {
    console.error(`Failed to parse model data from ${source}:`, error);
    return null;
  }
}

/** Build a default empty model from settings metadata */
function buildDefaultModel(settings: Settings): any {
  const apiMetadata = settings?.modeler_api?.metadata;
  return {
    id: settings?.modeler?.modelId || '',
    version: apiMetadata?.version || '1.0.0',
    metadata: {
      version: apiMetadata?.version || '1.0.0',
      label: apiMetadata?.label || t('New Workflow'),
      description: apiMetadata?.description || '',
      storage: apiMetadata?.storage || '',
      executable: apiMetadata?.executable !== false,
      template: apiMetadata?.template || false,
      tags: apiMetadata?.tags || [],
      changelog: apiMetadata?.changelog || '',
    },
    nodes: [],
    edges: [],
  };
}

// ============ Hook ============

export function useModelDataLoader({ settings, setViewportTarget }: UseModelDataLoaderProps) {
  const setNodes = useStore(state => state.setNodes);
  const setEdges = useStore(state => state.setEdges);
  const setComponents = useStore(state => state.setComponents);
  const setFavoriteComponents = useStore(state => state.setFavoriteComponents);
  const setContexts = useStore(state => state.setContexts);
  const setDependencies = useStore(state => state.setDependencies);
  const setSelectedContextId = useStore(state => state.setSelectedContextId);
  const setContextConfig = useStore(state => state.setContextConfig);
  const setComponentLabels = useStore(state => state.setComponentLabels);
  const setModelData = useStore(state => state.setModelData);
  const setSelectedNode = useStore(state => state.setSelectedNode);
  const setVisibleStartNodeIds = useStore(state => state.setVisibleStartNodeIds);

  // Process replay data
  const replayData = useMemo(() => settings.modeler?.replayData || [], [settings.modeler?.replayData]);

  // Initialize data from Drupal on mount
  useEffect(() => {
    // Load favorite components from settings
    if (settings?.modeler_api?.favorite_components) {
      setFavoriteComponents(settings.modeler_api.favorite_components);
    }

    // Load context config (default key/value pairs for new component configurations)
    if (settings?.modeler?.setContextConfig && typeof settings.modeler.setContextConfig === 'object') {
      setContextConfig(settings.modeler.setContextConfig);
    }

    // Load contexts from settings
    if (settings?.modeler_api?.contexts && Array.isArray(settings.modeler_api.contexts)) {
      setContexts(settings.modeler_api.contexts);

      // Auto-select context if specified and available
      if (settings.modeler?.selectContextId) {
        const contextExists = settings.modeler_api.contexts.some(
          ctx => ctx.id === settings.modeler!.selectContextId
        );
        if (contextExists) {
          setSelectedContextId(settings.modeler.selectContextId);
        }
      }
    }

    // Load dependency definitions from settings
    if (settings?.modeler_api?.dependencies && typeof settings.modeler_api.dependencies === 'object') {
      setDependencies(settings.modeler_api.dependencies);
    }

    // Load component labels from settings (model-owner-provided terminology)
    if (settings?.modeler_api?.component_labels && typeof settings.modeler_api.component_labels === 'object') {
      setComponentLabels(settings.modeler_api.component_labels);
      setActiveComponentLabels(settings.modeler_api.component_labels);
    }

    // Load components from settings
    if (settings?.modeler?.components) {
      setComponents(ensureGatewayComponent(settings.modeler.components));
    } else if (settings?.ownerComponents) {
      const flatComponents = flattenOwnerComponents(settings.ownerComponents);
      setComponents(ensureGatewayComponent(flatComponents));
    } else {
      // Fallback: if no components from settings, at least add the gateway
      setComponents([createGatewayComponent()]);
    }

    // Load model data from settings.modeler.modelData
    if (settings?.modeler?.modelData) {
      const parsed = parseAndMergeModelData(settings.modeler.modelData, settings, 'settings');
      if (parsed) {
        setModelData(parsed.modelData);
        setNodes(parsed.nodes);
        setEdges(parsed.edges);
        
        // Auto-select element if specified
        if (settings.modeler?.selectComponentId && parsed.nodes.length > 0) {
          const selectComponentId = settings.modeler.selectComponentId;
          const nodeToSelect = parsed.nodes.find(node => node.id === selectComponentId);
          if (nodeToSelect) {
            // Mark the node as selected in the nodes array
            const updatedNodes = parsed.nodes.map(node => ({
              ...node,
              selected: node.id === selectComponentId
            }));
            setNodes(updatedNodes);

            // If the selected component is a start node and there are
            // multiple start nodes, filter the canvas to show only its flow.
            const isStartNode = nodeToSelect.type === 'start';
            const startNodeCount = parsed.nodes.filter(n => n.type === 'start').length;
            if (isStartNode && startNodeCount > 1) {
              setVisibleStartNodeIds([nodeToSelect.id]);
            }
            
            // Set selection after a brief delay to ensure the store is updated
            setTimeout(() => {
              setSelectedNode(nodeToSelect);
              // Center on the selected node with a slightly longer delay to ensure ReactFlow is ready
              setTimeout(() => {
                // Check if this is a start node (start type or Events/Triggers category)
                const isStartType = isStartNode || 
                                  nodeToSelect.data?.category === 'Events' || 
                                  nodeToSelect.data?.category === 'Triggers';
                
                setViewportTarget({
                  type: isStartType ? 'top-align' : 'center',
                  nodeId: nodeToSelect.id,
                  options: { 
                    zoom: VIEWPORT.AUTO_CENTER_ZOOM,
                    duration: TIMING.VIEWPORT_PAN_DURATION 
                  }
                });
              }, TIMING.VIEWPORT_READY_DELAY);
            }, TIMING.SYNC_DELAY);
          }
        } else if (parsed.nodes.length > 0) {
          // No specific selection requested - just fit the view
          setTimeout(() => {
            setViewportTarget({
              type: 'fit',
              options: { padding: VIEWPORT.FIT_VIEW_PADDING }
            });
          }, 100);
        }
      }
    } else {
      // Fallback: try loading from hidden field
      const hiddenField = document.querySelector('[name="modeler_api_data"]') as HTMLInputElement;
      
      if (hiddenField && hiddenField.value) {
        const parsed = parseAndMergeModelData(hiddenField.value, settings, 'hidden field');
        if (parsed) {
          setModelData(parsed.modelData);
          setNodes(parsed.nodes);
          setEdges(parsed.edges);
          
          // Fit the workflow in view without auto-selecting any node
          if (parsed.nodes.length > 0) {
            setTimeout(() => {
              setViewportTarget({
                type: 'fit',
                options: { padding: VIEWPORT.FIT_VIEW_PADDING }
              });
            }, 100);
          }
        }
      }
      
      // Initialize with default model if no data found anywhere
      if (!settings?.modeler?.modelData && (!hiddenField || !hiddenField.value)) {
        setModelData(buildDefaultModel(settings));
      }
    }
  }, [settings, setComponents, setFavoriteComponents, setContexts, setDependencies, setSelectedContextId, setContextConfig, setComponentLabels, setModelData, setNodes, setEdges, setSelectedNode, setVisibleStartNodeIds, setViewportTarget]);

  return {
    replayData
  };
}
