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

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

test('plain single line is returned unchanged', () => {
  assert.equal(parseBlockMD('hello', parseInlineMD), 'hello');
});

test('heading levels', () => {
  assert.equal(parseBlockMD('# Heading', parseInlineMD), '<h1 data-md="#">Heading</h1>');
  assert.equal(parseBlockMD('### Three', parseInlineMD), '<h3 data-md="###">Three</h3>');
});

test('heading requires a space after the hashes', () => {
  // no space => not a heading, falls through to plain text
  assert.equal(parseBlockMD('#nospace', parseInlineMD), '#nospace');
});

test('inline markdown inside a heading is parsed', () => {
  assert.equal(
    parseBlockMD('# **b**', parseInlineMD),
    '<h1 data-md="#"><strong data-md="**">b</strong></h1>',
  );
});

test('heading without a parseInline function keeps the raw text', () => {
  assert.equal(parseBlockMD('# Heading', undefined), '<h1 data-md="#">Heading</h1>');
});

test('fenced code block without info string', () => {
  assert.equal(
    parseBlockMD('```\ncode\n```', parseInlineMD),
    '<pre data-md="```"><code>code\n</code></pre>',
  );
});

test('fenced code block with a language', () => {
  assert.equal(
    parseBlockMD('```js\ncode\n```', parseInlineMD),
    '<pre data-md="```"><code class="language-js">code\n</code></pre>',
  );
});

test('fenced code block with a filename adds language and data-label', () => {
  assert.equal(
    parseBlockMD('```example.json\ncode\n```', parseInlineMD),
    '<pre data-md="```"><code class="language-json" data-label="example.json">code\n</code></pre>',
  );
});

test('blockquote single line', () => {
  assert.equal(
    parseBlockMD('> quote', parseInlineMD),
    '<blockquote data-md=">">quote<br/></blockquote>',
  );
});

test('blockquote multiple lines', () => {
  assert.equal(
    parseBlockMD('> a\n> b', parseInlineMD),
    '<blockquote data-md=">">a<br/>b<br/></blockquote>',
  );
});

test('unordered list', () => {
  assert.equal(parseBlockMD('* item', parseInlineMD), '<ul data-md="*"><li><p>item</p></li></ul>');
});

test('ordered list', () => {
  assert.equal(
    parseBlockMD('1. item', parseInlineMD),
    '<ol data-md="1" start="1"><li><p>item</p></li></ol>',
  );
});

test('list with multiple items', () => {
  assert.equal(
    parseBlockMD('* a\n* b', parseInlineMD),
    '<ul data-md="*"><li><p>a</p></li><li><p>b</p></li></ul>',
  );
});

test('nested list opens a child list', () => {
  assert.equal(
    parseBlockMD('* a\n  * b', parseInlineMD),
    '<ul data-md="*"><li><p>a</p><ul data-md="*"><li><p>b</p></li></ul></ul>',
  );
});

test('inline markdown inside list items is parsed', () => {
  assert.equal(
    parseBlockMD('1. **b**', parseInlineMD),
    '<ol data-md="1" start="1"><li><p><strong data-md="**">b</strong></p></li></ol>',
  );
});

test('newlines are preserved as <br/>', () => {
  assert.equal(parseBlockMD('line1\nline2', parseInlineMD), 'line1<br/>line2');
});

test('empty lines are preserved as <br/>', () => {
  assert.equal(parseBlockMD('a\n\nb', parseInlineMD), 'a<br/><br/>b');
});

test('escaped block sequence is unescaped and not treated as a block', () => {
  assert.equal(parseBlockMD('\\# not heading', parseInlineMD), '# not heading');
});
