import { test } from 'node:test';
import assert from 'node:assert/strict';
import { beforeMatch, afterMatch, replaceMatch } from './utils';

test('beforeMatch returns the slice before the match', () => {
  const match = 'abXYcd'.match(/XY/)!;
  assert.equal(beforeMatch('abXYcd', match), 'ab');
});

test('beforeMatch is empty when the match is at the start', () => {
  const match = 'XYcd'.match(/XY/)!;
  assert.equal(beforeMatch('XYcd', match), '');
});

test('beforeMatch on a match without an index treats index as undefined', () => {
  // text.slice(0, undefined) returns the whole string
  const fakeMatch = ['X'] as unknown as RegExpMatchArray;
  assert.equal(beforeMatch('Xabc', fakeMatch), 'Xabc');
});

test('afterMatch returns the slice after the match', () => {
  const match = 'abXYcd'.match(/XY/)!;
  assert.equal(afterMatch('abXYcd', match), 'cd');
});

test('afterMatch is empty when the match runs to the end', () => {
  const match = 'abXY'.match(/XY/)!;
  assert.equal(afterMatch('abXY', match), '');
});

test('afterMatch handles a match at the start', () => {
  const match = 'XYcd'.match(/XY/)!;
  assert.equal(afterMatch('XYcd', match), 'cd');
});

test('afterMatch falls back to index 0 when match.index is missing', () => {
  // (undefined ?? 0) + match[0].length === 1, so it slices off the first char
  const fakeMatch = ['X'] as unknown as RegExpMatchArray;
  assert.equal(afterMatch('Xabc', fakeMatch), 'abc');
});

test('replaceMatch splices content between processed before/after parts', () => {
  const match = 'abXYcd'.match(/XY/)!;
  assert.deepEqual(
    replaceMatch('abXYcd', match, '<R>', (t) => [t]),
    ['ab', '<R>', 'cd'],
  );
});

test('replaceMatch applies processPart to the surrounding text', () => {
  const match = 'abXYcd'.match(/XY/)!;
  assert.deepEqual(
    replaceMatch('abXYcd', match, '<R>', (t) => [t.toUpperCase()]),
    ['AB', '<R>', 'CD'],
  );
});

test('replaceMatch keeps empty surrounding parts produced by processPart', () => {
  const match = 'XY'.match(/XY/)!;
  // empty before and after still flow through processPart
  assert.deepEqual(
    replaceMatch('XY', match, '<R>', (t) => [t]),
    ['', '<R>', ''],
  );
});

test('replaceMatch supports non-string content types', () => {
  const match = 'aXb'.match(/X/)!;
  const node = { type: 'node' };
  assert.deepEqual(
    replaceMatch('aXb', match, node, (t) => [t]),
    ['a', node, 'b'],
  );
});
