import { describe, expect, it } from 'vitest';
import { applySourceTextEdit } from './text-edit';
import {
  CANONICAL_LATEX_HARD_BREAK,
  CANONICAL_LATEX_PARAGRAPH_SEPARATOR,
  canonicalEmptySourceAnchor,
  createLatexInlineSplitMutation,
  createSourceBackedBlockDeletion,
} from './structural-break';

describe('R1 canonical LaTeX structural breaks', () => {
  it('uses blank-line source for Visual-generated paragraphs', () => {
    expect(CANONICAL_LATEX_PARAGRAPH_SEPARATOR).toBe('\n\n');
    expect(CANONICAL_LATEX_PARAGRAPH_SEPARATOR).not.toContain('\\par');
  });

  it('anchors empty editable bodies after horizontal padding without crossing a newline', () => {
    expect(canonicalEmptySourceAnchor('  \n', 0, 3)).toBe(2);
    expect(canonicalEmptySourceAnchor('   &', 0, 3)).toBe(3);
  });

  it('reuses surrounding newlines when deleting a block into one editable blank row', () => {
    const source = 'Before\nBLOCK\nAfter';
    const from = source.indexOf('BLOCK');
    const to = from + 'BLOCK'.length;
    const deletion = createSourceBackedBlockDeletion(source, { from, to });
    expect(deletion).toBeDefined();
    if (!deletion) return;
    expect(deletion.edit.text).toBe('\n');
    expect(applySourceTextEdit(source, deletion.edit)).toBe('Before\n\n\nAfter');
    expect(deletion.focusOffset).toBe('Before\n\n'.length);
  });

  it('uses a lexically terminated hard-break command', () => {
    expect(CANONICAL_LATEX_HARD_BREAK).toBe('\\newline{}');
    const source = 'AlphaBeta';
    const mutation = createLatexInlineSplitMutation(
      source,
      'Alpha'.length,
      'Alpha'.length,
      CANONICAL_LATEX_HARD_BREAK,
    );
    expect(mutation).toBeDefined();
    if (!mutation) return;
    expect(applySourceTextEdit(source, mutation.edit)).toBe('Alpha\\newline{}Beta');
    expect(mutation.focusOffset).toBe('Alpha\\newline{}'.length);
  });

  it('splits a formatted inline wrapper instead of injecting structure into its argument', () => {
    const source = '\\textbf{AlphaBeta}';
    const bodyFrom = source.indexOf('{') + 1;
    const bodyTo = source.lastIndexOf('}');
    const mutation = createLatexInlineSplitMutation(
      source,
      bodyFrom + 'Alpha'.length,
      bodyFrom + 'Alpha'.length,
      CANONICAL_LATEX_HARD_BREAK,
      { sourceFrom: 0, sourceTo: source.length, bodyFrom, bodyTo },
    );
    expect(mutation).toBeDefined();
    if (!mutation) return;
    expect(applySourceTextEdit(source, mutation.edit)).toBe(
      '\\textbf{Alpha}\\newline{}\\textbf{Beta}',
    );
  });

  it('preserves href metadata while splitting its editable label', () => {
    const source = '\\href{https://example.test}{AlphaBeta}';
    const bodyFrom = source.lastIndexOf('{') + 1;
    const bodyTo = source.lastIndexOf('}');
    const mutation = createLatexInlineSplitMutation(
      source,
      bodyFrom + 'Alpha'.length,
      bodyFrom + 'Alpha'.length,
      '\n\n',
      { sourceFrom: 0, sourceTo: source.length, bodyFrom, bodyTo },
    );
    expect(mutation).toBeDefined();
    if (!mutation) return;
    expect(applySourceTextEdit(source, mutation.edit)).toBe(
      '\\href{https://example.test}{Alpha}\n\n\\href{https://example.test}{Beta}',
    );
  });

  it('fails closed for an invalid wrapper range', () => {
    expect(
      createLatexInlineSplitMutation('Alpha', 2, 2, CANONICAL_LATEX_HARD_BREAK, {
        sourceFrom: 0,
        sourceTo: 5,
        bodyFrom: 3,
        bodyTo: 5,
      }),
    ).toBeUndefined();
  });
});
