"use strict";

const test = require("node:test");
const assert = require("node:assert/strict");
const workflow = require("../../Web/legacy-batch-selection-workflow.js");

test("legacy pointer gestures preserve MainForm selection and anchor semantics", () => {
  let selection = workflow.createSelection(8);
  selection = workflow.applyPointerSelection(selection, 3);
  assert.deepEqual(selection.selectedIndices, [3]);
  assert.equal(selection.anchorIndex, 3);

  selection = workflow.applyPointerSelection(selection, 5, { ctrlKey: true });
  assert.deepEqual(selection.selectedIndices, [3, 5]);
  assert.equal(selection.anchorIndex, 5);

  selection = workflow.applyPointerSelection(selection, 2, { shiftKey: true });
  assert.deepEqual(selection.selectedIndices, [2, 3, 4, 5]);
  assert.equal(selection.anchorIndex, 2);

  selection = workflow.applyPointerSelection(selection, 6, { ctrlKey: true, shiftKey: true });
  assert.deepEqual(selection.selectedIndices, [2, 3, 4, 5, 6]);
  assert.equal(selection.anchorIndex, 6);

  selection = workflow.applyPointerSelection(selection, 4, { ctrlKey: true });
  assert.deepEqual(selection.selectedIndices, [2, 3, 5, 6]);
  assert.equal(selection.anchorIndex, 4);
});

test("shift without an existing anchor safely selects only the clicked row", () => {
  const selection = workflow.applyPointerSelection(
    workflow.createSelection(4),
    2,
    { shiftKey: true });
  assert.deepEqual(selection.selectedIndices, [2]);
  assert.equal(selection.anchorIndex, 2);
});

test("double-click activation is allowed only for the single clicked selection", () => {
  assert.equal(workflow.canActivateSingle(workflow.createSelection(5, [2], 2), 2), true);
  assert.equal(workflow.canActivateSingle(workflow.createSelection(5, [2], 2), 1), false);
  assert.equal(workflow.canActivateSingle(workflow.createSelection(5, [1, 2], 2), 2), false);
  assert.equal(workflow.canActivateSingle(null, 0), false);
});

test("selection snapshots reject malformed or out-of-range state", () => {
  assert.throws(() => workflow.createSelection(-1), RangeError);
  assert.throws(() => workflow.createSelection(3, [3]), RangeError);
  assert.throws(() => workflow.createSelection(3, [0], 3), RangeError);
  assert.throws(() => workflow.applyPointerSelection(workflow.createSelection(3), -1), RangeError);
});

test("atomic batch materialization preserves source order and commits only after success", () => {
  const source = [{ code: "A" }, { code: "B" }, { code: "C" }];
  const playlist = [{ id: "existing" }];
  const entries = workflow.materializeAtomicBatch(source, (item, index) => ({
    id: `batch-${index}`,
    code: item.code
  }));
  playlist.push(...entries);
  assert.deepEqual(playlist.map(item => item.code || item.id), ["existing", "A", "B", "C"]);

  const unchanged = [...playlist];
  assert.throws(() => {
    const failed = workflow.materializeAtomicBatch(source, (item, index) => {
      if (index === 1) throw new Error("unsupported");
      return { id: `failed-${index}`, code: item.code };
    });
    playlist.push(...failed);
  }, /unsupported/u);
  assert.deepEqual(playlist, unchanged);
});

test("atomic batches reject empty, malformed, unsafe, or duplicate entries", () => {
  assert.throws(() => workflow.materializeAtomicBatch([], () => ({})), RangeError);
  assert.throws(() => workflow.materializeAtomicBatch([1], null), TypeError);
  assert.throws(() => workflow.materializeAtomicBatch([1], () => null), TypeError);
  assert.throws(() => workflow.materializeAtomicBatch([1], () => ({ id: "unsafe id" })), TypeError);
  assert.throws(
    () => workflow.materializeAtomicBatch([1, 2], () => ({ id: "duplicate" })),
    TypeError);
});
