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

import { createControllerBindingCapture } from './controller-binding-capture.js';

function createSnapshot(
  overrides: {
    axes?: number[];
    buttons?: Array<{ value: number; pressed?: boolean; touched?: boolean }>;
  } = {},
) {
  return {
    axes: overrides.axes ?? [0, 0, 0, 0, 0],
    buttons:
      overrides.buttons ??
      Array.from({ length: 12 }, () => ({
        value: 0,
        pressed: false,
        touched: false,
      })),
  };
}

test('controller binding capture waits for neutral-to-active button edge', () => {
  const capture = createControllerBindingCapture({
    triggerDeadzone: 0.5,
    stickDeadzone: 0.2,
  });

  const heldButtons = createSnapshot({
    buttons: [{ value: 1, pressed: true, touched: true }],
  });

  capture.arm({ actionId: 'toggleLookup', bindingType: 'discrete' }, heldButtons);

  assert.equal(capture.poll(heldButtons), null);

  const neutralButtons = createSnapshot();
  assert.equal(capture.poll(neutralButtons), null);

  const freshPress = createSnapshot({
    buttons: [{ value: 1, pressed: true, touched: true }],
  });
  assert.deepEqual(capture.poll(freshPress), {
    actionId: 'toggleLookup',
    bindingType: 'discrete',
    binding: { kind: 'button', buttonIndex: 0 },
  });
});

test('controller binding capture records fresh axis direction for discrete learn mode', () => {
  const capture = createControllerBindingCapture({
    triggerDeadzone: 0.5,
    stickDeadzone: 0.2,
  });

  capture.arm({ actionId: 'closeLookup', bindingType: 'discrete' }, createSnapshot());

  assert.deepEqual(capture.poll(createSnapshot({ axes: [0, 0, 0, -0.8] })), {
    actionId: 'closeLookup',
    bindingType: 'discrete',
    binding: { kind: 'axis', axisIndex: 3, direction: 'negative' },
  });
});

test('controller binding capture ignores analog drift inside deadzone', () => {
  const capture = createControllerBindingCapture({
    triggerDeadzone: 0.5,
    stickDeadzone: 0.3,
  });

  capture.arm({ actionId: 'mineCard', bindingType: 'discrete' }, createSnapshot());

  assert.equal(capture.poll(createSnapshot({ axes: [0.2, 0, 0, 0] })), null);
  assert.equal(capture.isArmed(), true);
});

test('controller binding capture emits axis binding for continuous learn mode', () => {
  const capture = createControllerBindingCapture({
    triggerDeadzone: 0.5,
    stickDeadzone: 0.2,
  });

  capture.arm(
    {
      actionId: 'leftStickHorizontal',
      bindingType: 'axis',
      dpadFallback: 'horizontal',
    },
    createSnapshot(),
  );

  assert.deepEqual(capture.poll(createSnapshot({ axes: [0, 0, 0, 0.9] })), {
    actionId: 'leftStickHorizontal',
    bindingType: 'axis',
    binding: { kind: 'axis', axisIndex: 3, dpadFallback: 'horizontal' },
  });
});

test('controller binding capture ignores button presses for continuous learn mode', () => {
  const capture = createControllerBindingCapture({
    triggerDeadzone: 0.5,
    stickDeadzone: 0.2,
  });

  capture.arm(
    {
      actionId: 'leftStickHorizontal',
      bindingType: 'axis',
      dpadFallback: 'horizontal',
    },
    createSnapshot(),
  );

  assert.equal(
    capture.poll(
      createSnapshot({
        buttons: [{ value: 1, pressed: true, touched: true }],
      }),
    ),
    null,
  );

  assert.deepEqual(capture.poll(createSnapshot({ axes: [0, 0, 0.75, 0, 0] })), {
    actionId: 'leftStickHorizontal',
    bindingType: 'axis',
    binding: { kind: 'axis', axisIndex: 2, dpadFallback: 'horizontal' },
  });
});
