/**
 * Tests for piece bookmark functionality
 */

import { describe, it, expect } from 'vitest';
import { handleKeyInput } from '../shared/prompt/index.js';
import { applyBookmarks, type SelectionOption } from '../features/pieceSelection/index.js';

describe('handleKeyInput - bookmark action', () => {
  const totalItems = 4;
  const optionCount = 3;
  const hasCancelOption = true;

  it('should return bookmark action for b key', () => {
    const result = handleKeyInput('b', 1, totalItems, hasCancelOption, optionCount);
    expect(result).toEqual({ action: 'bookmark', selectedIndex: 1 });
  });

  it('should return bookmark action with current index', () => {
    const result = handleKeyInput('b', 0, totalItems, hasCancelOption, optionCount);
    expect(result).toEqual({ action: 'bookmark', selectedIndex: 0 });
  });

  it('should return bookmark action at last option index', () => {
    const result = handleKeyInput('b', 2, totalItems, hasCancelOption, optionCount);
    expect(result).toEqual({ action: 'bookmark', selectedIndex: 2 });
  });

  it('should not interfere with existing key bindings', () => {
    // j/k should still work
    expect(handleKeyInput('j', 0, totalItems, hasCancelOption, optionCount)).toEqual({ action: 'move', newIndex: 1 });
    expect(handleKeyInput('k', 1, totalItems, hasCancelOption, optionCount)).toEqual({ action: 'move', newIndex: 0 });
    // Enter should still confirm
    expect(handleKeyInput('\r', 0, totalItems, hasCancelOption, optionCount)).toEqual({ action: 'confirm', selectedIndex: 0 });
    // Esc should still cancel
    expect(handleKeyInput('\x1B', 0, totalItems, hasCancelOption, optionCount)).toEqual({ action: 'cancel', cancelIndex: 3 });
  });
});

describe('applyBookmarks', () => {
  const options: SelectionOption[] = [
    { label: 'alpha', value: 'alpha' },
    { label: 'beta', value: 'beta' },
    { label: 'gamma', value: 'gamma' },
    { label: 'delta', value: 'delta' },
  ];

  it('should add [*] suffix to bookmarked items without changing order', () => {
    const result = applyBookmarks(options, ['gamma']);
    expect(result[2]!.label).toBe('gamma [*]');
    expect(result[2]!.value).toBe('gamma');
    expect(result).toHaveLength(4);
  });

  it('should preserve original order of all items', () => {
    const result = applyBookmarks(options, ['gamma']);
    expect(result.map((o) => o.value)).toEqual(['alpha', 'beta', 'gamma', 'delta']);
  });

  it('should handle multiple bookmarks preserving original order', () => {
    const result = applyBookmarks(options, ['delta', 'alpha']);
    expect(result[0]!.value).toBe('alpha');
    expect(result[0]!.label).toBe('alpha [*]');
    expect(result[3]!.value).toBe('delta');
    expect(result[3]!.label).toBe('delta [*]');
    expect(result.map((o) => o.value)).toEqual(['alpha', 'beta', 'gamma', 'delta']);
  });

  it('should return unchanged options when no bookmarks', () => {
    const result = applyBookmarks(options, []);
    expect(result).toEqual(options);
  });

  it('should ignore bookmarks that do not match any option', () => {
    const result = applyBookmarks(options, ['nonexistent']);
    expect(result).toEqual(options);
  });

  it('should not mutate original options', () => {
    const original = options.map((o) => ({ ...o }));
    applyBookmarks(options, ['gamma']);
    expect(options).toEqual(original);
  });

  it('should work with category-prefixed values', () => {
    const categoryOptions: SelectionOption[] = [
      { label: 'simple', value: 'simple' },
      { label: '📁 frontend/', value: '__category__:frontend' },
      { label: '📁 backend/', value: '__category__:backend' },
    ];
    // Only piece values should match; categories are not bookmarkable
    const result = applyBookmarks(categoryOptions, ['simple']);
    expect(result[0]!.label).toBe('simple [*]');
    expect(result.map((o) => o.value)).toEqual(['simple', '__category__:frontend', '__category__:backend']);
  });

  it('should handle all items bookmarked', () => {
    const result = applyBookmarks(options, ['alpha', 'beta', 'gamma', 'delta']);
    expect(result.every((o) => o.label.endsWith(' [*]'))).toBe(true);
    expect(result.map((o) => o.value)).toEqual(['alpha', 'beta', 'gamma', 'delta']);
  });
});
