import { describe, it, expect, beforeEach } from 'vitest';

/**
 * Tests for input history logic extracted from useInputHistory.
 * We test the pure state transitions directly rather than using
 * React testing utilities to avoid react-dom version conflicts.
 */

const MAX_HISTORY = 50;

function createHistoryState() {
  let history: string[] = [];
  let historyIndex = -1;
  let savedInput = '';

  function addToHistory(input: string): void {
    if (!input.trim()) return;
    if (history[0] === input) return;
    history = [input, ...history].slice(0, MAX_HISTORY);
    historyIndex = -1;
  }

  function navigateUp(currentInput: string): string | null {
    if (history.length === 0) return null;
    if (historyIndex === -1) {
      savedInput = currentInput;
    }
    const nextIndex = Math.min(historyIndex + 1, history.length - 1);
    historyIndex = nextIndex;
    return history[nextIndex] ?? null;
  }

  function navigateDown(): string | null {
    if (historyIndex <= 0) {
      historyIndex = -1;
      return savedInput;
    }
    const nextIndex = historyIndex - 1;
    historyIndex = nextIndex;
    return history[nextIndex] ?? null;
  }

  function resetNavigation(): void {
    historyIndex = -1;
  }

  function getHistoryLength(): number {
    return history.length;
  }

  return { addToHistory, navigateUp, navigateDown, resetNavigation, getHistoryLength };
}

describe('useInputHistory (logic)', () => {
  let h: ReturnType<typeof createHistoryState>;

  beforeEach(() => {
    h = createHistoryState();
  });

  it('adds to history on submit', () => {
    h.addToHistory('hello');
    h.addToHistory('world');
    // navigateUp should return 'world' first (most recent)
    const val = h.navigateUp('');
    expect(val).toBe('world');
  });

  it('does not add empty strings to history', () => {
    h.addToHistory('');
    h.addToHistory('   ');
    const val = h.navigateUp('');
    expect(val).toBeNull();
  });

  it('navigateDown after up returns saved input', () => {
    h.addToHistory('first');
    const up = h.navigateUp('current');
    expect(up).toBe('first');
    const down = h.navigateDown();
    expect(down).toBe('current');
  });

  it('does not add duplicate consecutive entries', () => {
    h.addToHistory('same');
    h.addToHistory('same');
    expect(h.getHistoryLength()).toBe(1);
  });

  it('caps history at MAX_HISTORY entries', () => {
    for (let i = 0; i < 55; i++) {
      h.addToHistory(`entry-${i}`);
    }
    expect(h.getHistoryLength()).toBe(50);
    // Navigate to the oldest entry
    let val: string | null = null;
    for (let i = 0; i < 60; i++) {
      val = h.navigateUp('');
    }
    // Oldest entry at index 49 = entry-5 (entries 54 down to 5, 50 total)
    expect(val).toBe('entry-5');
  });

  it('navigateUp returns null when history is empty', () => {
    const val = h.navigateUp('something');
    expect(val).toBeNull();
  });

  it('navigateUp cycles through multiple entries', () => {
    h.addToHistory('a');
    h.addToHistory('b');
    h.addToHistory('c');
    expect(h.navigateUp('')).toBe('c');
    expect(h.navigateUp('c')).toBe('b');
    expect(h.navigateUp('b')).toBe('a');
  });

  it('resetNavigation resets index to -1', () => {
    h.addToHistory('test');
    h.navigateUp('');
    h.resetNavigation();
    // After reset, navigateUp from index -1 returns most recent again
    const val = h.navigateUp('');
    expect(val).toBe('test');
  });
});
