import assert from 'node:assert/strict';
import test from 'node:test';

import { BrowserInputSink } from '../public/js/input.js';

class FakePointerEvent {
  constructor(type, init) {
    this.type = type;
    Object.assign(this, init);
    this.movementX = 0;
    this.movementY = 0;
  }
}

test('mobile fire and look fallbacks emit SDL-compatible pointer events', () => {
  const events = [];
  const target = {
    ownerDocument: { defaultView: { PointerEvent: FakePointerEvent } },
    getBoundingClientRect() {
      return { left: 10, top: 20, width: 200, height: 100 };
    },
    dispatchEvent(event) {
      events.push(event);
      return true;
    }
  };
  const sink = new BrowserInputSink({ target, adapter: null });

  sink.action('fire', true, 'touch:7');
  sink.look(12.5, -7);
  sink.action('fire', false, 'touch:7');

  assert.deepEqual(events.map((event) => event.type), ['pointerdown', 'pointermove', 'pointerup']);
  assert.ok(events.every((event) => event instanceof FakePointerEvent));
  assert.ok(events.every((event) => event.pointerType === 'mouse' && event.isPrimary));
  assert.ok(events.every((event) => event.pointerId === events[0].pointerId));
  assert.deepEqual(
    events.map((event) => [event.button, event.buttons]),
    [[0, 1], [-1, 1], [0, 0]]
  );
  assert.equal(events[1].movementX, 12.5);
  assert.equal(events[1].movementY, -7);
  assert.equal(events[1].clientX, 122.5);
  assert.equal(events[1].clientY, 63);
});

test('touch and gamepad menu actions return to the HTML launcher', () => {
  const nativeActions = [];
  const menuSources = [];
  const sink = new BrowserInputSink({
    target: null,
    adapter: { inputAction: (...parts) => nativeActions.push(parts) },
    onMenu: ({ source }) => menuSources.push(source)
  });

  sink.action('menu', true, 'touch:4');
  sink.action('menu', false, 'touch:4');
  sink.action('menu', true, 'gamepad:0');

  assert.deepEqual(menuSources, ['touch:4', 'gamepad:0']);
  assert.deepEqual(nativeActions, []);
});
