import assert from 'node:assert/strict';
import { test } from 'node:test';
import { dropSlot, moveBy, moveToSlot, type Box } from '../src/lib/reorder-model.ts';

const box = (left: number, top: number): Box => ({ left, top, width: 30, height: 24 });

const wrapped = [box(0, 0), box(34, 0), box(68, 0), box(0, 28), box(34, 28)];

test('a pointer left of a chip centre lands before it', () => {
  assert.deepEqual(dropSlot(wrapped, 40, 10), { slot: 1, after: false });
  assert.deepEqual(dropSlot(wrapped, 2, 10), { slot: 0, after: false });
});

test('a pointer right of every chip in a row lands after its last chip', () => {
  assert.deepEqual(dropSlot(wrapped, 200, 10), { slot: 3, after: true });
  assert.deepEqual(dropSlot(wrapped, 200, 30), { slot: 5, after: true });
});

test('the nearest row wins when the pointer is above or below the chips', () => {
  assert.deepEqual(dropSlot(wrapped, 40, -50), { slot: 1, after: false });
  assert.deepEqual(dropSlot(wrapped, 40, 90), { slot: 4, after: false });
  assert.deepEqual(dropSlot(wrapped, 10, 27), { slot: 3, after: false });
});

test('chips of slightly different heights share a row', () => {
  const mixed = [box(0, 0), { left: 34, top: 2, width: 12, height: 20 }, box(50, 0)];
  assert.deepEqual(dropSlot(mixed, 100, 10), { slot: 3, after: true });
});

test('an empty list always lands at the start', () => {
  assert.deepEqual(dropSlot([], 10, 10), { slot: 0, after: false });
});

test('moving to a slot after the source accounts for the removed item', () => {
  assert.deepEqual(moveToSlot(['a', 'b', 'c', 'd'], 0, 3), ['b', 'c', 'a', 'd']);
  assert.deepEqual(moveToSlot(['a', 'b', 'c', 'd'], 0, 4), ['b', 'c', 'd', 'a']);
  assert.deepEqual(moveToSlot(['a', 'b', 'c', 'd'], 3, 1), ['a', 'd', 'b', 'c']);
});

test('moving onto its own slot returns the same list', () => {
  const list = ['a', 'b', 'c'];
  assert.equal(moveToSlot(list, 1, 1), list);
  assert.equal(moveToSlot(list, 1, 2), list);
  assert.equal(moveToSlot(list, 5, 0), list);
  assert.equal(moveToSlot(list, -1, 0), list);
});

test('moving never mutates the input and clamps the slot', () => {
  const list = ['a', 'b', 'c'];
  assert.deepEqual(moveToSlot(list, 0, 99), ['b', 'c', 'a']);
  assert.deepEqual(moveToSlot(list, 2, -4), ['c', 'a', 'b']);
  assert.deepEqual(list, ['a', 'b', 'c']);
});

test('moving by a step swaps neighbours and stops at the ends', () => {
  const list = ['a', 'b', 'c'];
  assert.deepEqual(moveBy(list, 0, 1), ['b', 'a', 'c']);
  assert.deepEqual(moveBy(list, 2, -1), ['a', 'c', 'b']);
  assert.equal(moveBy(list, 0, -1), list);
  assert.equal(moveBy(list, 2, 1), list);
});
