import { test } from 'node:test';
import assert from 'node:assert/strict';
import { runInlineRule, runInlineRules } from './runner';
import { parseInlineMD } from './parser';
import { BoldRule, ItalicRule1, StrikeRule } from './rules';
import { InlineMDRule } from './type';

// A trivial rule that wraps the matched token in <X>...</X>.
const makeRule = (token: string, tag: string): InlineMDRule => ({
  match: (text) => text.match(new RegExp(token)),
  html: (parse, match) => `<${tag}>${parse(match[0])}</${tag}>`,
});

test('runInlineRule applies a matching rule', () => {
  assert.equal(runInlineRule('**b**', BoldRule, parseInlineMD), '<strong data-md="**">b</strong>');
});

test('runInlineRule returns undefined when the rule does not match', () => {
  assert.equal(runInlineRule('plain', BoldRule, parseInlineMD), undefined);
});

test('runInlineRule recursively parses surrounding text', () => {
  // bold matches in the middle; text on both sides is re-parsed (here it is plain)
  assert.equal(
    runInlineRule('pre **mid** post', BoldRule, parseInlineMD),
    'pre <strong data-md="**">mid</strong> post',
  );
});

test('runInlineRules returns undefined when no rule matches', () => {
  assert.equal(runInlineRules('plain text', [BoldRule, ItalicRule1], parseInlineMD), undefined);
});

test('runInlineRules picks the earliest-matching rule regardless of rule order', () => {
  // italic appears before bold in the text, so italic wins even though Bold is listed first
  assert.equal(
    runInlineRules('a *i* **b**', [BoldRule, ItalicRule1], parseInlineMD),
    'a <i data-md="*">i</i> <strong data-md="**">b</strong>',
  );
});

test('runInlineRules breaks index ties by rule order (first listed wins)', () => {
  // Two synthetic rules both match at index 0; the first in the list wins.
  const aRule = makeRule('a', 'A');
  const a2Rule = makeRule('a', 'B');
  assert.equal(runInlineRules('a', [aRule, a2Rule], parseInlineMD), '<A>a</A>');
  assert.equal(runInlineRules('a', [a2Rule, aRule], parseInlineMD), '<B>a</B>');
});

test('runInlineRules earliest index wins even when a later-listed rule matches sooner', () => {
  // Strike token "~~s~~" is at index 0; bold token is later in the string.
  assert.equal(
    runInlineRules('~~s~~ **b**', [BoldRule, StrikeRule], parseInlineMD),
    '<s data-md="~~">s</s> <strong data-md="**">b</strong>',
  );
});
