import { describe, it, expect, beforeEach } from 'vitest';
import { pressable } from './pressable.js';
import { mountHost, connectTrait, spyEvent, resetDOM } from '../test-helpers.js';

describe('pressable', () => {
  beforeEach(resetDOM);

  it('sets data-pressable-pressed on pointerdown, removes on pointerup', () => {
    const host = mountHost();
    connectTrait(pressable, host);
    host.dispatchEvent(new PointerEvent('pointerdown'));
    expect(host.hasAttribute('data-pressable-pressed')).toBe(true);
    host.dispatchEvent(new PointerEvent('pointerup'));
    expect(host.hasAttribute('data-pressable-pressed')).toBe(false);
  });

  it('dispatches "press" event on pointerup', () => {
    const host = mountHost();
    connectTrait(pressable, host);
    const spy = spyEvent(host, 'press');
    host.dispatchEvent(new PointerEvent('pointerdown'));
    host.dispatchEvent(new PointerEvent('pointerup'));
    expect(spy.count).toBe(1);
  });

  it('dispatches "press" on Enter/Space keyup', () => {
    const host = mountHost();
    connectTrait(pressable, host);
    const spy = spyEvent(host, 'press');
    host.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
    host.dispatchEvent(new KeyboardEvent('keyup', { key: 'Enter' }));
    expect(spy.count).toBe(1);
    host.dispatchEvent(new KeyboardEvent('keydown', { key: ' ' }));
    host.dispatchEvent(new KeyboardEvent('keyup', { key: ' ' }));
    expect(spy.count).toBe(2);
  });

  it('respects [disabled] — no event, no attribute toggle', () => {
    const host = mountHost('button', { disabled: '' });
    connectTrait(pressable, host);
    const spy = spyEvent(host, 'press');
    host.dispatchEvent(new PointerEvent('pointerdown'));
    expect(host.hasAttribute('data-pressable-pressed')).toBe(false);
    host.dispatchEvent(new PointerEvent('pointerup'));
    expect(spy.count).toBe(0);
  });

  it('clears pressed state on pointerleave (canceled press)', () => {
    const host = mountHost();
    connectTrait(pressable, host);
    const spy = spyEvent(host, 'press');
    host.dispatchEvent(new PointerEvent('pointerdown'));
    expect(host.hasAttribute('data-pressable-pressed')).toBe(true);
    host.dispatchEvent(new PointerEvent('pointerleave'));
    expect(host.hasAttribute('data-pressable-pressed')).toBe(false);
    host.dispatchEvent(new PointerEvent('pointerup'));
    expect(spy.count).toBe(0);
  });

  it('disconnect removes all listeners and clears attribute', () => {
    const host = mountHost();
    const inst = connectTrait(pressable, host);
    host.dispatchEvent(new PointerEvent('pointerdown'));
    expect(host.hasAttribute('data-pressable-pressed')).toBe(true);
    inst.disconnect(host);
    expect(host.hasAttribute('data-pressable-pressed')).toBe(false);
    // Re-firing events post-disconnect is a no-op
    const spy = spyEvent(host, 'press');
    host.dispatchEvent(new PointerEvent('pointerdown'));
    host.dispatchEvent(new PointerEvent('pointerup'));
    expect(spy.count).toBe(0);
  });
});
