import { test } from 'node:test';
import assert from 'node:assert/strict';
import { parseInlineMD } from './parser';

test('empty string is returned unchanged', () => {
  assert.equal(parseInlineMD(''), '');
});

test('plain text without markdown is returned unchanged', () => {
  assert.equal(parseInlineMD('hello world'), 'hello world');
});

test('bold', () => {
  assert.equal(parseInlineMD('**bold**'), '<strong data-md="**">bold</strong>');
});

test('italic with asterisk', () => {
  assert.equal(parseInlineMD('*italic*'), '<i data-md="*">italic</i>');
});

test('italic with underscore', () => {
  assert.equal(parseInlineMD('_italic_'), '<i data-md="_">italic</i>');
});

test('underline', () => {
  assert.equal(parseInlineMD('__under__'), '<u data-md="__">under</u>');
});

test('strikethrough', () => {
  assert.equal(parseInlineMD('~~strike~~'), '<s data-md="~~">strike</s>');
});

test('inline code', () => {
  assert.equal(parseInlineMD('`code`'), '<code data-md="`">code</code>');
});

test('inline code does not parse markdown inside it', () => {
  // code is run before the other rules and does not re-parse its content
  assert.equal(parseInlineMD('`**bold**`'), '<code data-md="`">**bold**</code>');
});

test('spoiler', () => {
  assert.equal(parseInlineMD('||secret||'), '<span data-md="||" data-mx-spoiler>secret</span>');
});

test('link', () => {
  assert.equal(
    parseInlineMD('[alt](https://example.com)'),
    '<a data-md href="https://example.com">alt</a>',
  );
});

test('escaped markdown characters are unescaped to literal text', () => {
  assert.equal(parseInlineMD('\\*notbold\\*'), '*notbold*');
  assert.equal(parseInlineMD('a\\_b'), 'a_b');
});

test('nesting: italic inside bold', () => {
  assert.equal(
    parseInlineMD('**bold *italic***'),
    '<strong data-md="**">bold <i data-md="*">italic</i></strong>',
  );
});

test('nesting: bold inside link alt text', () => {
  assert.equal(
    parseInlineMD('[**b**](https://e.com)'),
    '<a data-md href="https://e.com"><strong data-md="**">b</strong></a>',
  );
});

test('nesting: bold inside spoiler', () => {
  assert.equal(
    parseInlineMD('||**b**||'),
    '<span data-md="||" data-mx-spoiler><strong data-md="**">b</strong></span>',
  );
});

test('adjacent tokens of different types are both parsed', () => {
  assert.equal(parseInlineMD('**a**_b_'), '<strong data-md="**">a</strong><i data-md="_">b</i>');
});

test('text surrounding a token is preserved', () => {
  assert.equal(parseInlineMD('pre **mid** post'), 'pre <strong data-md="**">mid</strong> post');
});

test('two separate tokens are parsed in their text order', () => {
  assert.equal(parseInlineMD('*a* **b**'), '<i data-md="*">a</i> <strong data-md="**">b</strong>');
  assert.equal(parseInlineMD('__a__ _b_'), '<u data-md="__">a</u> <i data-md="_">b</i>');
});

test('code takes precedence and is resolved before other inline rules', () => {
  assert.equal(parseInlineMD('`a` *b*'), '<code data-md="`">a</code> <i data-md="*">b</i>');
});

test('unclosed token is returned as literal text', () => {
  assert.equal(parseInlineMD('**unclosed'), '**unclosed');
});

test('markdown characters inside a URL are not parsed (negative lookbehind)', () => {
  assert.equal(parseInlineMD('https://e.com/*path*'), 'https://e.com/*path*');
});
