import { describe, test, expect, vi } from 'vitest';
import { clickableProps } from './a11y';

function makeKeyEvent(key: string) {
  return {
    key,
    preventDefault: vi.fn(),
  } as unknown as Parameters<ReturnType<typeof clickableProps>['onKeyDown']>[0];
}

describe('clickableProps', () => {
  test('sets role=button and tabIndex=0', () => {
    const props = clickableProps(() => {});
    expect(props.role).toBe('button');
    expect(props.tabIndex).toBe(0);
  });

  test('onClick invokes the callback', () => {
    const onActivate = vi.fn();
    const props = clickableProps(onActivate);
    props.onClick();
    expect(onActivate).toHaveBeenCalledTimes(1);
  });

  test('onKeyDown invokes the callback and preventDefaults on Enter', () => {
    const onActivate = vi.fn();
    const props = clickableProps(onActivate);
    const e = makeKeyEvent('Enter');
    props.onKeyDown(e);
    expect(onActivate).toHaveBeenCalledTimes(1);
    expect(e.preventDefault).toHaveBeenCalledTimes(1);
  });

  test('onKeyDown invokes the callback and preventDefaults on Space', () => {
    const onActivate = vi.fn();
    const props = clickableProps(onActivate);
    const e = makeKeyEvent(' ');
    props.onKeyDown(e);
    expect(onActivate).toHaveBeenCalledTimes(1);
    expect(e.preventDefault).toHaveBeenCalledTimes(1);
  });

  test('onKeyDown ignores other keys', () => {
    const onActivate = vi.fn();
    const props = clickableProps(onActivate);
    const e = makeKeyEvent('Tab');
    props.onKeyDown(e);
    expect(onActivate).not.toHaveBeenCalled();
    expect(e.preventDefault).not.toHaveBeenCalled();
  });

  test('onKeyDown activates when the event target is the row itself', () => {
    const onActivate = vi.fn();
    const props = clickableProps(onActivate);
    const rowEl = {};
    const e = {
      key: 'Enter',
      target: rowEl,
      currentTarget: rowEl,
      preventDefault: vi.fn(),
    } as unknown as Parameters<ReturnType<typeof clickableProps>['onKeyDown']>[0];
    props.onKeyDown(e);
    expect(onActivate).toHaveBeenCalledTimes(1);
    expect(e.preventDefault).toHaveBeenCalledTimes(1);
  });

  test('onKeyDown ignores a bubbled event from a nested control (e.g. a child button)', () => {
    const onActivate = vi.fn();
    const props = clickableProps(onActivate);
    const rowEl = {};
    const childButtonEl = {};
    const e = {
      key: 'Enter',
      target: childButtonEl,
      currentTarget: rowEl,
      preventDefault: vi.fn(),
    } as unknown as Parameters<ReturnType<typeof clickableProps>['onKeyDown']>[0];
    props.onKeyDown(e);
    expect(onActivate).not.toHaveBeenCalled();
    expect(e.preventDefault).not.toHaveBeenCalled();
  });
});
