import type { AlgorithmDefinition } from '@/lib/visualizations/types';

/**
 * Tree structure (level order: [4, 2, 6, 1, 3, 5, 7]):
 *
 *          4 (root)
 *        /   \
 *       2     6
 *      / \   / \
 *     1   3 5   7
 *
 * BFS (Level-order) output: [4, 2, 6, 1, 3, 5, 7]
 */

// Node IDs for our tree
const NODE_4 = 'n4';
const NODE_2 = 'n2';
const NODE_6 = 'n6';
const NODE_1 = 'n1';
const NODE_3 = 'n3';
const NODE_5 = 'n5';
const NODE_7 = 'n7';

// Helper to create tree state with specific node states
function createTreeState(nodeStates: Record<string, 'normal' | 'current' | 'visiting' | 'visited' | 'highlighted'>) {
  return {
    id: 'tree',
    label: 'Binary Search Tree',
    rootId: NODE_4,
    nodes: [
      { id: NODE_4, value: 4, state: nodeStates[NODE_4] ?? 'normal', left: NODE_2, right: NODE_6 },
      { id: NODE_2, value: 2, state: nodeStates[NODE_2] ?? 'normal', left: NODE_1, right: NODE_3 },
      { id: NODE_6, value: 6, state: nodeStates[NODE_6] ?? 'normal', left: NODE_5, right: NODE_7 },
      { id: NODE_1, value: 1, state: nodeStates[NODE_1] ?? 'normal', left: null, right: null },
      { id: NODE_3, value: 3, state: nodeStates[NODE_3] ?? 'normal', left: null, right: null },
      { id: NODE_5, value: 5, state: nodeStates[NODE_5] ?? 'normal', left: null, right: null },
      { id: NODE_7, value: 7, state: nodeStates[NODE_7] ?? 'normal', left: null, right: null },
    ],
  };
}

// Helper to create queue state
function createQueueState(values: number[], highlightFront = false, newRear = false) {
  return {
    id: 'bfs-queue',
    label: 'Queue',
    elements: values.map((v, i) => ({
      id: `queue-${v}-${i}`,
      value: v,
      state: (highlightFront && i === 0 ? 'highlighted' : newRear && i === values.length - 1 ? 'enqueued' : 'normal') as 'normal' | 'highlighted' | 'enqueued' | 'dequeued',
    })),
  };
}

// Helper to create output array state
function createOutputState(values: (number | null)[], highlightIndex?: number) {
  const maxLen = 7;
  const elements = [];
  for (let i = 0; i < maxLen; i++) {
    const val = values[i];
    elements.push({
      value: val ?? 0,
      index: i,
      state: (val === null ? 'dimmed' : i === highlightIndex ? 'highlighted' : 'success') as 'normal' | 'highlighted' | 'dimmed' | 'success' | 'comparing',
    });
  }
  return {
    id: 'output',
    label: 'Output Array',
    elements,
  };
}

export const bfsAlgorithm: AlgorithmDefinition = {
  id: 'bfs',
  title: 'Breadth-First Search (BFS)',
  slug: 'bfs',
  pattern: {
    name: 'BFS',
    description:
      'Use a queue to explore nodes level by level, visiting all nodes at the current depth before moving deeper.',
  },
  problemStatement:
    'Given a binary tree, traverse it level by level (breadth-first) and return the values in the order visited.',
  intuition:
    'BFS explores nodes in waves outward from the root. Using a queue ensures we process nodes in the order they were discovered - first in, first out (FIFO). This naturally produces level-order traversal.',
  code: {
    language: 'python',
    code: `def bfs(root):
    if not root:
        return []

    result = []
    queue = [root]

    while queue:
        # Dequeue front node
        node = queue.pop(0)
        result.append(node.val)

        # Enqueue children (left first, then right)
        if node.left:
            queue.append(node.left)
        if node.right:
            queue.append(node.right)

    return result`,
  },
  initialExample: {
    input: { tree: [4, 2, 6, 1, 3, 5, 7] },
    expected: [4, 2, 6, 1, 3, 5, 7],
  },
  steps: [
    // ==========================================
    // Phase 1: Problem (2 steps)
    // ==========================================
    {
      id: 'problem-1',
      phase: 'problem',
      explanation:
        'We have a binary tree. Our goal is to visit all nodes level by level, from left to right at each level.',
      dataState: {
        arrays: [],
        pointers: [],
        variables: [],
        calculations: [],
        trees: [createTreeState({})],
        queues: [createQueueState([])],
      },
    },
    {
      id: 'problem-2',
      phase: 'problem',
      explanation:
        'For this tree: Level 0 has [4], Level 1 has [2, 6], Level 2 has [1, 3, 5, 7]. Expected output: [4, 2, 6, 1, 3, 5, 7].',
      dataState: {
        arrays: [createOutputState([null, null, null, null, null, null, null])],
        pointers: [],
        variables: [],
        calculations: [],
        trees: [createTreeState({ [NODE_4]: 'highlighted', [NODE_2]: 'visiting', [NODE_6]: 'visiting' })],
        queues: [createQueueState([])],
      },
    },

    // ==========================================
    // Phase 2: Intuition (3 steps)
    // ==========================================
    {
      id: 'intuition-1',
      phase: 'intuition',
      explanation:
        'BFS uses a queue (FIFO). We start by adding the root, then repeatedly: dequeue one node, add its value to result, and enqueue its children.',
      dataState: {
        arrays: [createOutputState([null, null, null, null, null, null, null])],
        pointers: [],
        variables: [],
        calculations: [],
        trees: [createTreeState({ [NODE_4]: 'current' })],
        queues: [createQueueState([4])],
      },
    },
    {
      id: 'intuition-2',
      phase: 'intuition',
      explanation:
        'The queue acts as a "to-visit" list. When we dequeue a node, its children join the back of the queue. This ensures we finish each level before starting the next.',
      dataState: {
        arrays: [createOutputState([4, null, null, null, null, null, null], 0)],
        pointers: [],
        variables: [],
        calculations: [],
        trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'current', [NODE_6]: 'visiting' })],
        queues: [createQueueState([2, 6], true)],
      },
    },
    {
      id: 'intuition-3',
      phase: 'intuition',
      explanation:
        'Key insight: nodes discovered first are processed first (FIFO). A node\'s children are always behind other nodes at the same level in the queue.',
      dataState: {
        arrays: [createOutputState([4, 2, null, null, null, null, null])],
        pointers: [],
        variables: [],
        calculations: [],
        trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_6]: 'current', [NODE_1]: 'visiting', [NODE_3]: 'visiting' })],
        queues: [createQueueState([6, 1, 3], true)],
      },
    },

    // ==========================================
    // Phase 3: Pattern (2 steps)
    // ==========================================
    {
      id: 'pattern-1',
      phase: 'pattern',
      explanation:
        'BFS pattern: (1) Initialize queue with root, (2) While queue not empty: dequeue, process, enqueue children.',
      dataState: {
        arrays: [createOutputState([null, null, null, null, null, null, null])],
        pointers: [],
        variables: [],
        calculations: [],
        trees: [createTreeState({})],
        queues: [createQueueState([])],
      },
    },
    {
      id: 'pattern-2',
      phase: 'pattern',
      explanation:
        'The queue ensures level-order: all Level N nodes are processed before any Level N+1 nodes, because children are always added to the rear.',
      dataState: {
        arrays: [createOutputState([null, null, null, null, null, null, null])],
        pointers: [],
        variables: [
          { id: 'queue', name: 'queue', value: 'FIFO' },
          { id: 'result', name: 'result', value: '[]' },
        ],
        calculations: [],
        trees: [createTreeState({ [NODE_4]: 'current' })],
        queues: [createQueueState([4])],
      },
    },

    // ==========================================
    // Phase 4: Code (3 steps)
    // ==========================================
    {
      id: 'code-1',
      phase: 'code',
      explanation:
        'Initialize: empty result list, queue containing just the root node.',
      codeLine: 5,
      codeHighlightLines: [5, 6, 7],
      dataState: {
        arrays: [createOutputState([null, null, null, null, null, null, null])],
        pointers: [],
        variables: [
          { id: 'result', name: 'result', value: '[]' },
        ],
        calculations: [],
        trees: [createTreeState({ [NODE_4]: 'current' })],
        queues: [createQueueState([4])],
      },
    },
    {
      id: 'code-2',
      phase: 'code',
      explanation:
        'Main loop: While queue is not empty, dequeue the front node and add its value to result.',
      codeLine: 10,
      codeHighlightLines: [9, 10, 11, 12],
      dataState: {
        arrays: [createOutputState([4, null, null, null, null, null, null], 0)],
        pointers: [],
        variables: [],
        calculations: [],
        trees: [createTreeState({ [NODE_4]: 'visited' })],
        queues: [createQueueState([])],
      },
    },
    {
      id: 'code-3',
      phase: 'code',
      explanation:
        'After processing a node, enqueue its left child (if exists), then right child (if exists). This maintains left-to-right order within each level.',
      codeLine: 15,
      codeHighlightLines: [14, 15, 16, 17, 18],
      dataState: {
        arrays: [createOutputState([4, null, null, null, null, null, null])],
        pointers: [],
        variables: [],
        calculations: [],
        trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visiting', [NODE_6]: 'visiting' })],
        queues: [createQueueState([2, 6], false, true)],
      },
    },

    // ==========================================
    // Phase 5: Execution (12 steps)
    // ==========================================
    {
      id: 'exec-1',
      phase: 'execution',
      explanation:
        'Start: queue = [4], result = []. The root node is ready to be processed.',
      codeLine: 7,
      dataState: {
        arrays: [createOutputState([null, null, null, null, null, null, null])],
        pointers: [],
        variables: [
          { id: 'result', name: 'result', value: '[]' },
        ],
        calculations: [],
        trees: [createTreeState({ [NODE_4]: 'current' })],
        queues: [createQueueState([4], true)],
      },
    },
    {
      id: 'exec-2',
      phase: 'execution',
      explanation:
        'Dequeue 4 (the root). Add to result. Result: [4]. Now enqueue its children: 2 (left), 6 (right).',
      codeLine: 12,
      dataState: {
        arrays: [createOutputState([4, null, null, null, null, null, null], 0)],
        pointers: [],
        variables: [
          { id: 'node', name: 'node', value: 4 },
          { id: 'result', name: 'result', value: '[4]' },
        ],
        calculations: [],
        trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visiting', [NODE_6]: 'visiting' })],
        queues: [createQueueState([2, 6], false, true)],
      },
    },
    {
      id: 'exec-3',
      phase: 'execution',
      explanation:
        'Queue: [2, 6]. Dequeue 2 (front). Add to result. Result: [4, 2]. Enqueue children: 1, 3.',
      codeLine: 12,
      dataState: {
        arrays: [createOutputState([4, 2, null, null, null, null, null], 1)],
        pointers: [],
        variables: [
          { id: 'node', name: 'node', value: 2, previousValue: 4 },
          { id: 'result', name: 'result', value: '[4, 2]' },
        ],
        calculations: [],
        trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_6]: 'visiting', [NODE_1]: 'visiting', [NODE_3]: 'visiting' })],
        queues: [createQueueState([6, 1, 3], false, true)],
      },
    },
    {
      id: 'exec-4',
      phase: 'execution',
      explanation:
        'Queue: [6, 1, 3]. Dequeue 6 (front). Add to result. Result: [4, 2, 6]. Enqueue children: 5, 7.',
      codeLine: 12,
      dataState: {
        arrays: [createOutputState([4, 2, 6, null, null, null, null], 2)],
        pointers: [],
        variables: [
          { id: 'node', name: 'node', value: 6, previousValue: 2 },
          { id: 'result', name: 'result', value: '[4, 2, 6]' },
        ],
        calculations: [],
        trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_6]: 'visited', [NODE_1]: 'visiting', [NODE_3]: 'visiting', [NODE_5]: 'visiting', [NODE_7]: 'visiting' })],
        queues: [createQueueState([1, 3, 5, 7], false, true)],
      },
    },
    {
      id: 'exec-5',
      phase: 'execution',
      explanation:
        'Level 1 complete! Queue: [1, 3, 5, 7] - all Level 2 nodes. Dequeue 1. No children to enqueue.',
      codeLine: 12,
      dataState: {
        arrays: [createOutputState([4, 2, 6, 1, null, null, null], 3)],
        pointers: [],
        variables: [
          { id: 'node', name: 'node', value: 1, previousValue: 6 },
          { id: 'result', name: 'result', value: '[4, 2, 6, 1]' },
        ],
        calculations: [],
        trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_6]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'visiting', [NODE_5]: 'visiting', [NODE_7]: 'visiting' })],
        queues: [createQueueState([3, 5, 7], true)],
      },
    },
    {
      id: 'exec-6',
      phase: 'execution',
      explanation:
        'Queue: [3, 5, 7]. Dequeue 3. Result: [4, 2, 6, 1, 3]. Node 3 is a leaf (no children).',
      codeLine: 12,
      dataState: {
        arrays: [createOutputState([4, 2, 6, 1, 3, null, null], 4)],
        pointers: [],
        variables: [
          { id: 'node', name: 'node', value: 3, previousValue: 1 },
          { id: 'result', name: 'result', value: '[4, 2, 6, 1, 3]' },
        ],
        calculations: [],
        trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_6]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'visited', [NODE_5]: 'visiting', [NODE_7]: 'visiting' })],
        queues: [createQueueState([5, 7], true)],
      },
    },
    {
      id: 'exec-7',
      phase: 'execution',
      explanation:
        'Queue: [5, 7]. Dequeue 5. Result: [4, 2, 6, 1, 3, 5]. Node 5 is a leaf (no children).',
      codeLine: 12,
      dataState: {
        arrays: [createOutputState([4, 2, 6, 1, 3, 5, null], 5)],
        pointers: [],
        variables: [
          { id: 'node', name: 'node', value: 5, previousValue: 3 },
          { id: 'result', name: 'result', value: '[4, 2, 6, 1, 3, 5]' },
        ],
        calculations: [],
        trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_6]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'visited', [NODE_5]: 'visited', [NODE_7]: 'visiting' })],
        queues: [createQueueState([7], true)],
      },
    },
    {
      id: 'exec-8',
      phase: 'execution',
      explanation:
        'Queue: [7]. Dequeue 7. Result: [4, 2, 6, 1, 3, 5, 7]. Node 7 is a leaf (no children).',
      codeLine: 12,
      dataState: {
        arrays: [createOutputState([4, 2, 6, 1, 3, 5, 7], 6)],
        pointers: [],
        variables: [
          { id: 'node', name: 'node', value: 7, previousValue: 5 },
          { id: 'result', name: 'result', value: '[4, 2, 6, 1, 3, 5, 7]' },
        ],
        calculations: [],
        trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_6]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'visited', [NODE_5]: 'visited', [NODE_7]: 'visited' })],
        queues: [createQueueState([])],
      },
    },
    {
      id: 'exec-9',
      phase: 'execution',
      explanation:
        'Queue is empty! All nodes have been visited. Final result: [4, 2, 6, 1, 3, 5, 7] - perfect level-order traversal.',
      codeLine: 20,
      dataState: {
        arrays: [createOutputState([4, 2, 6, 1, 3, 5, 7])],
        pointers: [],
        variables: [
          { id: 'result', name: 'result', value: '[4, 2, 6, 1, 3, 5, 7]' },
        ],
        calculations: [],
        trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_6]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'visited', [NODE_5]: 'visited', [NODE_7]: 'visited' })],
        queues: [createQueueState([])],
      },
    },
  ],
};
