import type { SelectedScript } from '@/application/Context/State/Selection/Script/SelectedScript';
import { indentText } from '@/application/Common/Text/IndentText';
import { formatAssertionMessage } from '@tests/shared/FormatAssertionMessage';

export function expectEqualSelectedScripts(
  actual: readonly SelectedScript[],
  expected: readonly SelectedScript[],
) {
  expectSameScriptIds(actual, expected);
  expectSameRevertStates(actual, expected);
}

function expectSameScriptIds(
  actual: readonly SelectedScript[],
  expected: readonly SelectedScript[],
) {
  const existingScriptIds = expected.map((script) => script.id).sort();
  const expectedScriptIds = actual.map((script) => script.id).sort();
  expect(existingScriptIds).to.deep.equal(expectedScriptIds, formatAssertionMessage([
    'Unexpected script IDs.',
    `Expected: ${expectedScriptIds.join(', ')}`,
    `Actual: ${existingScriptIds.join(', ')}`,
  ]));
}

function expectSameRevertStates(
  actual: readonly SelectedScript[],
  expected: readonly SelectedScript[],
) {
  const scriptsWithDifferentRevertStates = actual
    .filter((script) => {
      const other = expected.find((existing) => existing.id === script.id);
      if (!other) {
        throw new Error(`Script "${script.id}" does not exist in expected scripts: ${JSON.stringify(expected, null, '\t')}`);
      }
      return script.revert !== other.revert;
    });
  expect(scriptsWithDifferentRevertStates).to.have.lengthOf(0, formatAssertionMessage([
    'Scripts with different revert states:',
    scriptsWithDifferentRevertStates
      .map((s) => indentText([
        `Script ID: "${s.id}"`,
        `Actual revert state: "${s.revert}"`,
        `Expected revert state: "${expected.find((existing) => existing.id === s.id)?.revert ?? 'unknown'}"`,
      ].join('\n')))
      .join('\n---\n'),
  ]));
}
