/**
 * FootswitchMode Context — provides the current mode and mode switching
 * to all footswitch components.
 */

import { createContext, useContext, useState, useCallback, type ReactNode } from 'react';
import type { FootswitchMode, ScribbleStripData, PedalState, PedalBlock } from '../types';
import { apiPost, activatePreset } from "./hooks/usePedalState";

// ── Context Shape ─────────────────────────────────────────────

interface FootswitchModeContextValue {
  mode: FootswitchMode;
  setMode: (mode: FootswitchMode) => void;
  /** Scribble strip data for each footswitch position (0–7) */
  scribbleData: ScribbleStripData[];
  /** Handle a footswitch press at a given position */
  handleFootswitch: (index: number) => void;
  /** Handle secondary action (double-tap / long-press) at a given position */
  handleSecondary: (index: number) => void;
  /** Current banks/presets for preset mode */
  currentBankIndex: number;
  currentPresetIndex: number;
  setBank: (bank: number) => void;
  setPreset: (preset: number) => void;
  /** Whether the preset has been modified */
  dirty: boolean;
}

const FootswitchModeContext = createContext<FootswitchModeContextValue | null>(null);

// ── Mode-specific scribble strip generators ───────────────────

function stompScribbles(
  blocks: PedalBlock[],
  _state: PedalState | null,
): ScribbleStripData[] {
  const items: ScribbleStripData[] = [];
  for (let i = 0; i < 8; i++) {
    const block = blocks[i];
    if (block) {
      items.push({
        key: `stomp-${block.id}`,
        label: block.title.length > 6 ? block.title.slice(0, 6) : block.title,
        sublabel: block.bypassed ? 'BYP' : 'ON',
        color: block.bypassed ? 'off' : 'green',
        active: !block.bypassed,
        bypassed: block.bypassed,
      });
    } else {
      items.push({
        key: `stomp-empty-${i}`,
        label: '—',
        sublabel: '',
        color: 'off',
        active: false,
        bypassed: false,
      });
    }
  }
  return items;
}

function presetScribbles(
  state: PedalState | null,
  bankIndex: number,
  bankNames: string[],
): ScribbleStripData[] {
  const items: ScribbleStripData[] = [];

  // FS 0-1: Bank navigation
  items.push({
    key: 'bank-down',
    label: 'BANK',
    sublabel: bankIndex > 0 ? `${bankNames[bankIndex - 1] || '−'}` : '—',
    color: 'blue',
    active: bankIndex > 0,
  });
  items.push({
    key: 'bank-up',
    label: 'BANK',
    sublabel: bankIndex < bankNames.length - 1 ? `${bankNames[bankIndex + 1] || '+'}` : '—',
    color: 'blue',
    active: bankIndex < bankNames.length - 1,
  });

  // FS 2-7: Preset slots
  for (let i = 0; i < 6; i++) {
    const presetIdx = i;
    const isActive = state?.current_preset?.program === presetIdx &&
                     state?.current_preset?.bank === bankIndex;
    items.push({
      key: `preset-${presetIdx}`,
      label: String(presetIdx + 1),
      sublabel: state?.current_preset && state.current_preset.program === presetIdx
        ? state.current_preset.name : '',
      color: isActive ? 'green' : 'off',
      active: isActive,
    });
  }

  return items;
}

function snapshotScribbles(
  snapshots: { name: string; active: boolean }[],
): ScribbleStripData[] {
  const items: ScribbleStripData[] = [];
  for (let i = 0; i < 8; i++) {
    const snap = snapshots[i];
    if (snap) {
      items.push({
        key: `snapshot-${i}`,
        label: snap.name.length > 6 ? snap.name.slice(0, 6) : (snap.name || `Snap ${i + 1}`),
        sublabel: snap.active ? 'ACTIVE' : '',
        color: snap.active ? 'amber' : 'off',
        active: snap.active,
      });
    } else {
      items.push({
        key: `snapshot-empty-${i}`,
        label: `Snap ${i + 1}`,
        sublabel: '',
        color: 'off',
        active: false,
      });
    }
  }
  return items;
}

function comboScribbles(
  blocks: PedalBlock[],
  state: PedalState | null,
  bankNames: string[],
  bankIndex: number,
): ScribbleStripData[] {
  // Combo = first 4 stomp + bank/preset info on last 4
  const stomp = stompScribbles(blocks.slice(0, 4), state);

  // FS 4: bank down, FS 5: bank up, FS 6-7: preset select
  return [
    ...stomp.slice(0, 4),
    {
      key: 'bank-down',
      label: 'BANK',
      sublabel: bankIndex > 0 ? '▼' : '—',
      color: 'blue',
      active: bankIndex > 0,
    },
    {
      key: 'bank-up',
      label: 'BANK',
      sublabel: bankIndex < bankNames.length - 1 ? '▲' : '—',
      color: 'blue',
      active: bankIndex < bankNames.length - 1,
    },
    {
      key: 'preset-select',
      label: state?.current_preset?.name?.slice(0, 6) || '—',
      sublabel: state?.current_preset ? `B${bankIndex + 1}` : '',
      color: 'amber',
      active: true,
    },
    {
      key: 'global-bypass',
      label: 'BYP',
      sublabel: state?.bypass ? 'ON' : 'OFF',
      color: state?.bypass ? 'red' : 'off',
      active: !!state?.bypass,
    },
  ];
}

// ── Provider ──────────────────────────────────────────────────

interface FootswitchModeProviderProps {
  children: ReactNode;
  state: PedalState | null;
  connected: boolean;
  refresh: () => void;
  blocks: PedalBlock[];
  bankNames: string[];
  /** Current snapshot definitions */
  snapshots: { name: string; active: boolean }[];
  /** Called when a block toggle needs to happen */
  onToggleBlock?: (blockId: number, bypassed: boolean) => void;
}

export function FootswitchModeProvider({
  children,
  state,
  connected,
  refresh,
  blocks,
  bankNames,
  snapshots,
  onToggleBlock,
}: FootswitchModeProviderProps) {
  const [mode, setMode] = useState<FootswitchMode>('stomp');
  const [currentBankIndex, setCurrentBankIndex] = useState(0);
  const [currentPresetIndex, setCurrentPresetIndex] = useState(0);
  const [dirty, setDirty] = useState(false);

  // Generate scribble data based on mode
  let scribbleData: ScribbleStripData[];
  switch (mode) {
    case 'stomp':
      scribbleData = stompScribbles(blocks, state);
      break;
    case 'preset':
      scribbleData = presetScribbles(state, currentBankIndex, bankNames);
      break;
    case 'snapshot':
      scribbleData = snapshotScribbles(snapshots);
      break;
    case 'combo':
      scribbleData = comboScribbles(blocks, state, bankNames, currentBankIndex);
      break;
    default:
      scribbleData = stompScribbles(blocks, state);
  }

  const handleFootswitch = useCallback((index: number) => {
    switch (mode) {
      case 'stomp': {
        const block = blocks[index];
        if (block && onToggleBlock) {
          onToggleBlock(block.id, !block.bypassed);
        }
        break;
      }
      case 'preset': {
        // FS 0 = bank down, FS 1 = bank up, FS 2-7 = presets
        if (index === 0) {
          setCurrentBankIndex(prev => Math.max(0, prev - 1));
        } else if (index === 1) {
          setCurrentBankIndex(prev => Math.min(bankNames.length - 1, prev + 1));
        } else {
          const presetIndex = index - 2;
          if (connected) {
            activatePreset(currentBankIndex, presetIndex).then(() => refresh());
            setCurrentPresetIndex(presetIndex);
          }
        }
        break;
      }
      case 'snapshot': {
        // Recall snapshot at index
        if (connected) {
          apiPost(`/api/snapshots/${index}/recall`).catch(() => {});
        }
        break;
      }
      case 'combo': {
        // FS 0-3 = stomp toggles, FS 4 = bank down, FS 5 = bank up,
        // FS 6 = open preset browser, FS 7 = global bypass
        if (index < 4) {
          const block = blocks[index];
          if (block && onToggleBlock) {
            onToggleBlock(block.id, !block.bypassed);
          }
        } else if (index === 4) {
          setCurrentBankIndex(prev => Math.max(0, prev - 1));
        } else if (index === 5) {
          setCurrentBankIndex(prev => Math.min(bankNames.length - 1, prev + 1));
        } else if (index === 6) {
          setMode('preset');
        } else if (index === 7) {
          if (connected) {
            apiPost('/api/bypass', { bypass: !state?.bypass }).catch(() => {});
          }
        }
        break;
      }
    }
  }, [mode, blocks, onToggleBlock, connected, currentBankIndex, bankNames, state, refresh]);

  const handleSecondary = useCallback((index: number) => {
    // Double-tap / long-press secondary actions per mode
    switch (mode) {
      case 'stomp': {
        // Secondary: toggle tuner on FS 7 (last footswitch), or reset block params
        if (index === 7 && connected) {
          apiPost('/api/tuner', { enabled: !state?.tuner_enabled }).catch(() => {});
        }
        break;
      }
      case 'preset': {
        // Secondary on bank switches: jump to first/last bank
        if (index === 0) {
          setCurrentBankIndex(0);
        } else if (index === 1) {
          setCurrentBankIndex(bankNames.length - 1);
        }
        break;
      }
      case 'snapshot': {
        // Secondary: save current state to snapshot
        if (connected) {
          apiPost(`/api/snapshots/${index}/save`).catch(() => {});
        }
        break;
      }
      case 'combo': {
        // Secondary on stomp blocks: edit block params (would open param panel)
        // Secondary on bypass: enter tuner mode
        if (index === 7 && connected) {
          apiPost('/api/tuner', { enabled: !state?.tuner_enabled }).catch(() => {});
        }
        break;
      }
    }
  }, [mode, state, connected, bankNames]);

  const setBank = useCallback((bank: number) => {
    setCurrentBankIndex(bank);
  }, []);

  const setPreset = useCallback((preset: number) => {
    setCurrentPresetIndex(preset);
    if (connected) {
      activatePreset(currentBankIndex, preset).then(() => refresh());
    }
  }, [connected, currentBankIndex, refresh]);

  const value: FootswitchModeContextValue = {
    mode,
    setMode,
    scribbleData,
    handleFootswitch,
    handleSecondary,
    currentBankIndex,
    currentPresetIndex,
    setBank,
    setPreset,
    dirty,
  };

  return (
    <FootswitchModeContext.Provider value={value}>
      {children}
    </FootswitchModeContext.Provider>
  );
}

// ── Consumer Hook ─────────────────────────────────────────────

export function useFootswitchMode(): FootswitchModeContextValue {
  const ctx = useContext(FootswitchModeContext);
  if (!ctx) {
    throw new Error('useFootswitchMode must be used within a FootswitchModeProvider');
  }
  return ctx;
}
