import { describe, test, expect } from 'vitest';
import {
  normalizeNativeKey,
  normalizeDomKeyEvent,
  matchesBinding,
  resolvePageTurn,
} from '@/utils/keybinding';
import { HardwarePageTurnerSettings } from '@/types/settings';

describe('normalizeNativeKey', () => {
  test('maps a known native key to a friendly label', () => {
    expect(normalizeNativeKey('MediaNext')).toEqual({
      source: 'native',
      id: 'MediaNext',
      label: 'Media Next',
    });
  });

  test('falls back to the raw id for an unknown native key', () => {
    expect(normalizeNativeKey('Keycode99')).toEqual({
      source: 'native',
      id: 'Keycode99',
      label: 'Keycode99',
    });
  });
});

describe('normalizeDomKeyEvent', () => {
  test('uses event.code and a friendly label for a known key', () => {
    const event = { code: 'ArrowLeft', key: 'ArrowLeft' } as KeyboardEvent;
    expect(normalizeDomKeyEvent(event)).toEqual({
      source: 'dom',
      id: 'ArrowLeft',
      label: 'Arrow Left',
    });
  });

  test('falls back to event.key when event.code is empty', () => {
    const event = { code: '', key: 'MediaTrackNext' } as KeyboardEvent;
    expect(normalizeDomKeyEvent(event)).toEqual({
      source: 'dom',
      id: 'MediaTrackNext',
      label: 'Media Next',
    });
  });
});

describe('matchesBinding', () => {
  const binding = { source: 'native' as const, id: 'MediaNext', label: 'Media Next' };

  test('matches same source and id', () => {
    expect(matchesBinding(binding, { source: 'native', id: 'MediaNext' })).toBe(true);
  });

  test('rejects different id', () => {
    expect(matchesBinding(binding, { source: 'native', id: 'MediaPrevious' })).toBe(false);
  });

  test('rejects different source', () => {
    expect(matchesBinding(binding, { source: 'dom', id: 'MediaNext' })).toBe(false);
  });

  test('rejects a null binding', () => {
    expect(matchesBinding(null, { source: 'native', id: 'MediaNext' })).toBe(false);
  });
});

describe('resolvePageTurn', () => {
  const settings: HardwarePageTurnerSettings = {
    enabled: true,
    bindings: {
      pagePrev: { source: 'native', id: 'MediaPrevious', label: 'Media Previous' },
      pageNext: { source: 'native', id: 'MediaNext', label: 'Media Next' },
      sectionPrev: { source: 'dom', id: 'PageUp', label: 'Page Up' },
      sectionNext: { source: 'dom', id: 'PageDown', label: 'Page Down' },
      refresh: { source: 'native', id: 'MediaPlayPause', label: 'Media Play/Pause' },
    },
  };

  test('returns "pagePrev" for the pagePrev binding', () => {
    expect(resolvePageTurn(settings, { source: 'native', id: 'MediaPrevious' })).toBe('pagePrev');
  });

  test('returns "pageNext" for the pageNext binding', () => {
    expect(resolvePageTurn(settings, { source: 'native', id: 'MediaNext' })).toBe('pageNext');
  });

  test('returns "sectionPrev" for the sectionPrev binding', () => {
    expect(resolvePageTurn(settings, { source: 'dom', id: 'PageUp' })).toBe('sectionPrev');
  });

  test('returns "sectionNext" for the sectionNext binding', () => {
    expect(resolvePageTurn(settings, { source: 'dom', id: 'PageDown' })).toBe('sectionNext');
  });

  test('returns "refresh" for the refresh binding', () => {
    expect(resolvePageTurn(settings, { source: 'native', id: 'MediaPlayPause' })).toBe('refresh');
  });

  test('returns null for an unbound key', () => {
    expect(resolvePageTurn(settings, { source: 'native', id: 'MediaFastForward' })).toBeNull();
  });

  test('returns null when the feature is disabled', () => {
    const disabled = { ...settings, enabled: false };
    expect(resolvePageTurn(disabled, { source: 'native', id: 'MediaNext' })).toBeNull();
  });
});
