const assert = require('assert');
const {
  boundaryMemberForEdge,
  edgeOpposite,
  findGroupSnapCandidate,
  findSnapCandidate,
  latestLayoutForHost,
  snapRectToEdge,
} = require('../app-ui/display-layout');

const localDisplays = [
  {
    displayId: 'left-display',
    rect: { x: 100, y: 100, width: 300, height: 200 },
  },
  {
    displayId: 'right-display',
    rect: { x: 450, y: 100, width: 300, height: 200 },
  },
];

{
  const candidate = findSnapCandidate(
    { x: 754, y: 130, width: 180, height: 120 },
    localDisplays,
    48
  );
  assert(candidate, 'a display near an edge should snap');
  assert.strictEqual(candidate.edge, 'right');
  assert.strictEqual(candidate.sourceDisplayId, 'right-display');
  assert.deepStrictEqual(candidate.rect, {
    x: 750,
    y: 140,
    width: 180,
    height: 120,
  });
}

{
  const candidate = findSnapCandidate(
    { x: -83, y: 125, width: 180, height: 120 },
    localDisplays,
    48
  );
  assert(candidate, 'left-edge snapping should be detected');
  assert.strictEqual(candidate.edge, 'left');
  assert.strictEqual(candidate.sourceDisplayId, 'left-display');
}

{
  const candidate = findSnapCandidate(
    { x: 510, y: -24, width: 180, height: 120 },
    localDisplays,
    48
  );
  assert(candidate, 'top-edge snapping should be detected');
  assert.strictEqual(candidate.edge, 'top');
  assert.strictEqual(candidate.sourceDisplayId, 'right-display');
}

{
  const candidate = findSnapCandidate(
    { x: 660, y: 140, width: 180, height: 120 },
    localDisplays,
    48
  );
  assert(candidate, 'dragging a display center onto an edge should snap');
  assert.strictEqual(candidate.edge, 'right');
  assert.strictEqual(candidate.sourceDisplayId, 'right-display');
}

{
  const candidate = findSnapCandidate(
    { x: 900, y: 500, width: 180, height: 120 },
    localDisplays,
    48
  );
  assert.strictEqual(candidate, null, 'a distant display should remain free while dragging');
}

assert.deepStrictEqual(
  snapRectToEdge(
    { x: 0, y: 0, width: 100, height: 80 },
    { x: 200, y: 100, width: 240, height: 160 },
    'bottom'
  ),
  { x: 270, y: 260, width: 100, height: 80 },
  'snapping should align and center displays along the chosen edge'
);

{
  const remoteMembers = [
    { id: 'remote-left', rect: { x: 0, y: 0, width: 120, height: 100 } },
    { id: 'remote-right', rect: { x: 120, y: 0, width: 120, height: 100 } },
  ];
  const localMembers = [
    { id: 'local', rect: { x: 300, y: 0, width: 100, height: 100 } },
  ];
  const candidate = findGroupSnapCandidate(
    remoteMembers,
    [{ groupId: 'local-machine', members: localMembers }],
    64
  );
  assert(candidate, 'a multi-display machine should snap as one group');
  assert.strictEqual(candidate.edge, 'left');
  assert.strictEqual(
    candidate.movingMemberId,
    'remote-right',
    'the exposed display should become the persisted target'
  );
  assert.strictEqual(candidate.sourceMemberId, 'local');
  assert.strictEqual(candidate.deltaX, 60);
}

{
  const localMembers = [
    { id: 'local-left', rect: { x: 240, y: 0, width: 100, height: 100 } },
  ];
  const remoteMembers = [
    { id: 'remote-left', rect: { x: 0, y: 0, width: 120, height: 100 } },
    { id: 'remote-right', rect: { x: 120, y: 0, width: 120, height: 100 } },
  ];
  const candidate = findGroupSnapCandidate(
    localMembers,
    [{ groupId: 'remote-host', members: remoteMembers }],
    64
  );
  assert(candidate, 'the local machine group should also be draggable');
  assert.strictEqual(candidate.edge, 'right');
  assert.strictEqual(candidate.movingMemberId, 'local-left');
  assert.strictEqual(candidate.sourceMemberId, 'remote-right');
  assert.strictEqual(edgeOpposite(candidate.edge), 'left');
}

assert.strictEqual(
  boundaryMemberForEdge([
    { id: 'left', rect: { x: 0, y: 0, width: 100, height: 100 } },
    { id: 'right', rect: { x: 100, y: 0, width: 100, height: 100 } },
  ], 'left').id,
  'right',
  'a group placed left should connect through its rightmost display'
);

{
  const latest = latestLayoutForHost({
    'remote::3': { edge: 'right', updatedAt: 10 },
    'remote::2': { edge: 'left', updatedAt: 20 },
    'other::1': { edge: 'top', updatedAt: 30 },
  }, 'remote');
  assert.strictEqual(latest.layoutId, 'remote::2');
  assert.strictEqual(latest.entry.edge, 'left');
}

console.log('display layout snapping tests passed');
