import { useState, useCallback, useMemo } from 'react';
import type {
  AttributeDAG,
  DAGNode,
  CrossoverPair,
  CrossoverConfig,
  CrossoverResult,
} from '../types';

const DEFAULT_CONFIG: CrossoverConfig = {
  enabledCrossTypes: ['same-category', 'cross-category'],
  maxPairsPerType: 10,
  autoGenerate: true,
};

export function useAttributeCrossover() {
  const [pairs, setPairs] = useState<CrossoverPair[]>([]);
  const [config, setConfig] = useState<CrossoverConfig>(DEFAULT_CONFIG);

  // Group nodes by category
  const groupNodesByCategory = useCallback((nodes: DAGNode[]): Record<string, DAGNode[]> => {
    return nodes.reduce((acc, node) => {
      if (!acc[node.category]) acc[node.category] = [];
      acc[node.category].push(node);
      return acc;
    }, {} as Record<string, DAGNode[]>);
  }, []);

  // Generate crossover pairs from two DAGs
  const generatePairs = useCallback((
    dagA: AttributeDAG,
    dagB: AttributeDAG
  ): CrossoverPair[] => {
    const newPairs: CrossoverPair[] = [];

    const nodesByCategoryA = groupNodesByCategory(dagA.nodes);
    const nodesByCategoryB = groupNodesByCategory(dagB.nodes);

    // Get all unique categories from both DAGs
    const categoriesA = Object.keys(nodesByCategoryA);
    const categoriesB = Object.keys(nodesByCategoryB);

    // Strategy 1: Cross matching categories (A's category X with B's category X)
    // This helps find how different objects approach the same category differently
    for (const category of categoriesA) {
      if (nodesByCategoryB[category]) {
        const nodesA = nodesByCategoryA[category].slice(0, config.maxPairsPerType);
        const nodesB = nodesByCategoryB[category].slice(0, config.maxPairsPerType);

        for (const nodeA of nodesA) {
          for (const nodeB of nodesB) {
            newPairs.push({
              id: `same-${nodeA.id}-${nodeB.id}`,
              sourcePathId: 'A',
              sourceNode: nodeA,
              targetPathId: 'B',
              targetNode: nodeB,
              crossType: `same-${category}`,
              selected: true,  // Default selected for same-category pairs
            });
          }
        }
      }
    }

    // Strategy 2: Cross different categories between A and B
    // This creates innovative combinations (e.g., A's materials with B's functions)
    for (const categoryA of categoriesA) {
      for (const categoryB of categoriesB) {
        // Skip if same category (already handled above)
        if (categoryA === categoryB) continue;

        const nodesA = nodesByCategoryA[categoryA].slice(0, 3);
        const nodesB = nodesByCategoryB[categoryB].slice(0, 3);

        if (nodesA.length > 0 && nodesB.length > 0) {
          for (const nodeA of nodesA) {
            for (const nodeB of nodesB) {
              newPairs.push({
                id: `cross-${nodeA.id}-${nodeB.id}`,
                sourcePathId: 'A',
                sourceNode: nodeA,
                targetPathId: 'B',
                targetNode: nodeB,
                crossType: `cross-${categoryA}-${categoryB}`,
                selected: false,  // Cross-category pairs default to not selected
              });
            }
          }
        }
      }
    }

    return newPairs;
  }, [groupNodesByCategory, config.maxPairsPerType]);

  // Apply generated pairs to state
  const applyPairs = useCallback((dagA: AttributeDAG, dagB: AttributeDAG) => {
    const newPairs = generatePairs(dagA, dagB);
    setPairs(newPairs);
    return newPairs;
  }, [generatePairs]);

  // Toggle pair selection
  const togglePairSelection = useCallback((pairId: string) => {
    setPairs(prev => prev.map(pair =>
      pair.id === pairId
        ? { ...pair, selected: !pair.selected }
        : pair
    ));
  }, []);

  // Select all pairs of a specific type
  const selectPairsByType = useCallback((crossType: string, selected: boolean) => {
    setPairs(prev => prev.map(pair =>
      pair.crossType === crossType
        ? { ...pair, selected }
        : pair
    ));
  }, []);

  // Select all pairs
  const selectAll = useCallback((selected: boolean) => {
    setPairs(prev => prev.map(pair => ({ ...pair, selected })));
  }, []);

  // Clear all pairs
  const clearPairs = useCallback(() => {
    setPairs([]);
  }, []);

  // Get pairs grouped by cross type
  const pairsByType = useMemo(() => {
    return pairs.reduce((acc, pair) => {
      if (!acc[pair.crossType]) acc[pair.crossType] = [];
      acc[pair.crossType].push(pair);
      return acc;
    }, {} as Record<string, CrossoverPair[]>);
  }, [pairs]);

  // Get selected pairs only
  const selectedPairs = useMemo(() => {
    return pairs.filter(p => p.selected);
  }, [pairs]);

  // Get cross type statistics
  const crossTypeStats = useMemo(() => {
    const stats: Record<string, { total: number; selected: number }> = {};
    for (const pair of pairs) {
      if (!stats[pair.crossType]) {
        stats[pair.crossType] = { total: 0, selected: 0 };
      }
      stats[pair.crossType].total++;
      if (pair.selected) {
        stats[pair.crossType].selected++;
      }
    }
    return stats;
  }, [pairs]);

  // Get result summary
  const result: CrossoverResult = useMemo(() => ({
    pairs,
    totalPairs: pairs.length,
  }), [pairs]);

  return {
    pairs,
    selectedPairs,
    pairsByType,
    crossTypeStats,
    config,
    result,
    setConfig,
    generatePairs,
    applyPairs,
    togglePairSelection,
    selectPairsByType,
    selectAll,
    clearPairs,
  };
}
