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

/**
 * Jump Game (LeetCode 55)
 *
 * Input: nums = [2, 3, 1, 1, 4]
 * Output: true (can reach last index)
 *
 * Greedy approach: Track maximum reachable position.
 * At each index i, if i > maxReach we're stuck. Otherwise update maxReach.
 */

// Helper to create array state with reachable range highlighted
function createJumpArray(
  values: number[],
  currentIndex: number | undefined,
  maxReach: number,
  showResult?: 'success' | 'failure'
) {
  return {
    id: 'nums',
    label: 'Jump Values',
    elements: values.map((value, index) => ({
      value,
      index,
      state: (showResult === 'success' && index <= maxReach
        ? 'success'
        : showResult === 'failure' && index > maxReach
        ? 'dimmed'
        : index === currentIndex
        ? 'highlighted'
        : index <= maxReach
        ? 'success'
        : 'normal') as ArrayElementState['state'],
    })),
  };
}

export const jumpGameAlgorithm: AlgorithmDefinition = {
  id: 'jump-game',
  title: 'Jump Game (Greedy)',
  slug: 'jump-game',
  pattern: {
    name: 'Greedy',
    description:
      'Make locally optimal choices at each step, tracking the farthest reachable position.',
  },
  problemStatement:
    'Given an array of non-negative integers nums, where nums[i] represents the maximum jump length from position i, determine if you can reach the last index starting from index 0.',
  intuition:
    'We don\'t need to track every possible path—just the farthest position we can reach. If at any point our current position exceeds the farthest reachable, we\'re stuck. Otherwise, we keep extending our reach.',
  code: {
    language: 'python',
    code: `def can_jump(nums: list[int]) -> bool:
    max_reach = 0

    for i in range(len(nums)):
        if i > max_reach:
            return False
        max_reach = max(max_reach, i + nums[i])

    return True`,
  },
  initialExample: {
    input: { nums: [2, 3, 1, 1, 4] },
    expected: true,
  },
  steps: [
    // ==========================================
    // Phase 1: Problem (2 steps)
    // ==========================================
    {
      id: 'problem-1',
      phase: 'problem',
      explanation:
        'Given nums = [2, 3, 1, 1, 4], can we reach the last index? Each value tells us the maximum jump length from that position.',
      dataState: {
        arrays: [createJumpArray([2, 3, 1, 1, 4], undefined, -1)],
        pointers: [],
        variables: [
          { id: 'goal', name: 'goal', value: 'reach index 4' },
        ],
        calculations: [],
      },
    },
    {
      id: 'problem-2',
      phase: 'problem',
      explanation:
        'Brute force: Try every possible path using BFS/DFS. This is O(2^n) in worst case. Can we do better with a greedy approach?',
      dataState: {
        arrays: [createJumpArray([2, 3, 1, 1, 4], 0, -1)],
        pointers: [],
        variables: [
          { id: 'brute', name: 'brute force', value: 'O(2^n)' },
        ],
        calculations: [],
      },
    },

    // ==========================================
    // Phase 2: Intuition (3 steps)
    // ==========================================
    {
      id: 'intuition-1',
      phase: 'intuition',
      explanation:
        'Key insight: We only care about the FARTHEST position we can reach, not HOW we get there. If we can reach index 4, we win—the path doesn\'t matter.',
      dataState: {
        arrays: [createJumpArray([2, 3, 1, 1, 4], undefined, -1)],
        pointers: [],
        variables: [
          { id: 'insight', name: 'insight', value: 'track max reach' },
        ],
        calculations: [],
      },
    },
    {
      id: 'intuition-2',
      phase: 'intuition',
      explanation:
        'From index 0, nums[0]=2 means we can reach indices 0, 1, or 2. From index 1, nums[1]=3 extends our reach to index 4. That\'s the greedy choice!',
      dataState: {
        arrays: [createJumpArray([2, 3, 1, 1, 4], 0, 2)],
        pointers: [
          { id: 'i', name: 'i', index: 0, color: 'left' },
          { id: 'maxReach', name: 'max_reach', index: 2, color: 'right' },
        ],
        variables: [
          { id: 'reach0', name: 'from 0', value: '0 + 2 = 2' },
        ],
        calculations: [],
      },
    },
    {
      id: 'intuition-3',
      phase: 'intuition',
      explanation:
        'At each position, we extend our reach if possible. If we ever find ourselves at a position beyond our max reach, we\'re stuck and return false.',
      dataState: {
        arrays: [createJumpArray([2, 3, 1, 1, 4], 1, 4)],
        pointers: [
          { id: 'i', name: 'i', index: 1, color: 'left' },
          { id: 'maxReach', name: 'max_reach', index: 4, color: 'right' },
        ],
        variables: [
          { id: 'reach1', name: 'from 1', value: '1 + 3 = 4' },
        ],
        calculations: [],
      },
    },

    // ==========================================
    // Phase 3: Pattern (2 steps)
    // ==========================================
    {
      id: 'pattern-1',
      phase: 'pattern',
      explanation:
        'Greedy property: The locally optimal choice (extending reach as far as possible) leads to a globally optimal solution.',
      dataState: {
        arrays: [createJumpArray([2, 3, 1, 1, 4], undefined, -1)],
        pointers: [],
        variables: [
          { id: 'greedy', name: 'greedy', value: 'local → global optimal' },
        ],
        calculations: [],
      },
    },
    {
      id: 'pattern-2',
      phase: 'pattern',
      explanation:
        'One pass solution: Track max_reach. For each index i, check if reachable (i ≤ max_reach), then update max_reach = max(max_reach, i + nums[i]). Return true if we finish the loop.',
      dataState: {
        arrays: [createJumpArray([2, 3, 1, 1, 4], undefined, -1)],
        pointers: [],
        variables: [
          { id: 'time', name: 'Time', value: 'O(n)' },
          { id: 'space', name: 'Space', value: 'O(1)' },
        ],
        calculations: [],
      },
    },

    // ==========================================
    // Phase 4: Code (3 steps)
    // ==========================================
    {
      id: 'code-1',
      phase: 'code',
      explanation:
        'Initialize max_reach = 0. We start at index 0, so our initial reachable range is just index 0.',
      codeLine: 2,
      codeHighlightLines: [2],
      dataState: {
        arrays: [createJumpArray([2, 3, 1, 1, 4], undefined, 0)],
        pointers: [
          { id: 'maxReach', name: 'max_reach', index: 0, color: 'right' },
        ],
        variables: [
          { id: 'maxReach', name: 'max_reach', value: 0 },
        ],
        calculations: [],
      },
    },
    {
      id: 'code-2',
      phase: 'code',
      explanation:
        'Loop through each index. If i > max_reach, we can\'t reach this position—return False. Otherwise, update max_reach to extend our reachable range.',
      codeLine: 4,
      codeHighlightLines: [4, 5, 6, 7],
      dataState: {
        arrays: [createJumpArray([2, 3, 1, 1, 4], undefined, 0)],
        pointers: [],
        variables: [
          { id: 'maxReach', name: 'max_reach', value: 0 },
        ],
        calculations: [],
      },
    },
    {
      id: 'code-3',
      phase: 'code',
      explanation:
        'If we complete the loop, we were able to reach or pass every index—return True. We can reach the last index!',
      codeLine: 9,
      codeHighlightLines: [9],
      dataState: {
        arrays: [createJumpArray([2, 3, 1, 1, 4], undefined, 4, 'success')],
        pointers: [],
        variables: [
          { id: 'result', name: 'result', value: 'True' },
        ],
        calculations: [],
      },
    },

    // ==========================================
    // Phase 5: Execution (~10 steps)
    // ==========================================
    // Process index 0
    {
      id: 'exec-1',
      phase: 'execution',
      explanation:
        'Initialize max_reach = 0. Start processing from index 0.',
      codeLine: 2,
      dataState: {
        arrays: [createJumpArray([2, 3, 1, 1, 4], undefined, 0)],
        pointers: [
          { id: 'maxReach', name: 'max_reach', index: 0, color: 'right' },
        ],
        variables: [
          { id: 'maxReach', name: 'max_reach', value: 0 },
        ],
        calculations: [],
      },
    },
    {
      id: 'exec-2',
      phase: 'execution',
      explanation:
        'i = 0: Check if reachable. Is 0 > max_reach (0)? No, we can reach index 0.',
      codeLine: 5,
      decision: {
        question: 'Is i > max_reach?',
        answer: '0 > 0 = false',
        action: 'Position is reachable, continue',
      },
      dataState: {
        arrays: [createJumpArray([2, 3, 1, 1, 4], 0, 0)],
        pointers: [
          { id: 'i', name: 'i', index: 0, color: 'left' },
          { id: 'maxReach', name: 'max_reach', index: 0, color: 'right' },
        ],
        variables: [
          { id: 'i', name: 'i', value: 0 },
          { id: 'maxReach', name: 'max_reach', value: 0 },
        ],
        calculations: [],
      },
    },
    {
      id: 'exec-3',
      phase: 'execution',
      explanation:
        'Update max_reach = max(0, 0 + 2) = 2. From index 0 with jump value 2, we can now reach up to index 2.',
      codeLine: 7,
      dataState: {
        arrays: [createJumpArray([2, 3, 1, 1, 4], 0, 2)],
        pointers: [
          { id: 'i', name: 'i', index: 0, color: 'left' },
          { id: 'maxReach', name: 'max_reach', index: 2, color: 'right' },
        ],
        variables: [
          { id: 'i', name: 'i', value: 0 },
          { id: 'maxReach', name: 'max_reach', value: 2, previousValue: 0, derivation: 'max(0, 0+2)' },
        ],
        calculations: [
          { id: 'calc-1', expression: 'max(0, 0+2)', result: '2', position: 'above' },
        ],
      },
    },

    // Process index 1
    {
      id: 'exec-4',
      phase: 'execution',
      explanation:
        'i = 1: Check if reachable. Is 1 > max_reach (2)? No, we can reach index 1.',
      codeLine: 5,
      decision: {
        question: 'Is i > max_reach?',
        answer: '1 > 2 = false',
        action: 'Position is reachable, continue',
      },
      dataState: {
        arrays: [createJumpArray([2, 3, 1, 1, 4], 1, 2)],
        pointers: [
          { id: 'i', name: 'i', index: 1, color: 'left' },
          { id: 'maxReach', name: 'max_reach', index: 2, color: 'right' },
        ],
        variables: [
          { id: 'i', name: 'i', value: 1, previousValue: 0 },
          { id: 'maxReach', name: 'max_reach', value: 2 },
        ],
        calculations: [],
      },
    },
    {
      id: 'exec-5',
      phase: 'execution',
      explanation:
        'Update max_reach = max(2, 1 + 3) = 4. From index 1 with jump value 3, we can now reach the last index!',
      codeLine: 7,
      dataState: {
        arrays: [createJumpArray([2, 3, 1, 1, 4], 1, 4)],
        pointers: [
          { id: 'i', name: 'i', index: 1, color: 'left' },
          { id: 'maxReach', name: 'max_reach', index: 4, color: 'right' },
        ],
        variables: [
          { id: 'i', name: 'i', value: 1 },
          { id: 'maxReach', name: 'max_reach', value: 4, previousValue: 2, derivation: 'max(2, 1+3)' },
        ],
        calculations: [
          { id: 'calc-2', expression: 'max(2, 1+3)', result: '4', position: 'above' },
        ],
      },
    },

    // Process index 2
    {
      id: 'exec-6',
      phase: 'execution',
      explanation:
        'i = 2: Check if reachable. Is 2 > max_reach (4)? No. Update max_reach = max(4, 2+1) = 4. No change.',
      codeLine: 7,
      decision: {
        question: 'Is i > max_reach?',
        answer: '2 > 4 = false',
        action: 'Position is reachable, continue',
      },
      dataState: {
        arrays: [createJumpArray([2, 3, 1, 1, 4], 2, 4)],
        pointers: [
          { id: 'i', name: 'i', index: 2, color: 'left' },
          { id: 'maxReach', name: 'max_reach', index: 4, color: 'right' },
        ],
        variables: [
          { id: 'i', name: 'i', value: 2, previousValue: 1 },
          { id: 'maxReach', name: 'max_reach', value: 4, derivation: 'max(4, 2+1) = 4' },
        ],
        calculations: [],
      },
    },

    // Process index 3
    {
      id: 'exec-7',
      phase: 'execution',
      explanation:
        'i = 3: Check if reachable. Is 3 > max_reach (4)? No. Update max_reach = max(4, 3+1) = 4. No change.',
      codeLine: 7,
      decision: {
        question: 'Is i > max_reach?',
        answer: '3 > 4 = false',
        action: 'Position is reachable, continue',
      },
      dataState: {
        arrays: [createJumpArray([2, 3, 1, 1, 4], 3, 4)],
        pointers: [
          { id: 'i', name: 'i', index: 3, color: 'left' },
          { id: 'maxReach', name: 'max_reach', index: 4, color: 'right' },
        ],
        variables: [
          { id: 'i', name: 'i', value: 3, previousValue: 2 },
          { id: 'maxReach', name: 'max_reach', value: 4, derivation: 'max(4, 3+1) = 4' },
        ],
        calculations: [],
      },
    },

    // Process index 4 (last)
    {
      id: 'exec-8',
      phase: 'execution',
      explanation:
        'i = 4: Check if reachable. Is 4 > max_reach (4)? No. Update max_reach = max(4, 4+4) = 8. We\'re at the last index!',
      codeLine: 7,
      decision: {
        question: 'Is i > max_reach?',
        answer: '4 > 4 = false',
        action: 'Position is reachable, continue',
      },
      dataState: {
        arrays: [createJumpArray([2, 3, 1, 1, 4], 4, 4)],
        pointers: [
          { id: 'i', name: 'i', index: 4, color: 'left' },
          { id: 'maxReach', name: 'max_reach', index: 4, color: 'right' },
        ],
        variables: [
          { id: 'i', name: 'i', value: 4, previousValue: 3 },
          { id: 'maxReach', name: 'max_reach', value: 8, previousValue: 4, derivation: 'max(4, 4+4)' },
        ],
        calculations: [
          { id: 'calc-3', expression: 'max(4, 4+4)', result: '8', position: 'above' },
        ],
      },
    },

    // Return result
    {
      id: 'exec-9',
      phase: 'execution',
      explanation:
        'Loop complete! We processed all indices without getting stuck. Return True—we can reach the last index.',
      codeLine: 9,
      dataState: {
        arrays: [createJumpArray([2, 3, 1, 1, 4], undefined, 4, 'success')],
        pointers: [],
        variables: [
          { id: 'result', name: 'result', value: 'True' },
        ],
        calculations: [],
      },
    },
    {
      id: 'exec-10',
      phase: 'execution',
      explanation:
        'Done! The greedy approach finds the answer in O(n) time and O(1) space by tracking only the maximum reachable position.',
      codeLine: 9,
      decision: {
        question: 'Why does greedy work here?',
        answer: 'We only need to know IF we can reach the end, not HOW',
        action: 'Tracking max reach is sufficient—no need to explore all paths',
      },
      dataState: {
        arrays: [createJumpArray([2, 3, 1, 1, 4], undefined, 4, 'success')],
        pointers: [],
        variables: [
          { id: 'result', name: 'result', value: 'True' },
          { id: 'time', name: 'Time', value: 'O(n)' },
          { id: 'space', name: 'Space', value: 'O(1)' },
        ],
        calculations: [],
      },
    },
  ],
};
