import { captureSourceAnchor, resolveSourceAnchor } from '../source-anchor';
import { describe, expect, it } from 'vitest';

describe('SourceAnchor', () => {
  it('captures context and resolves the same revision exactly', () => {
    const source = 'alpha beta gamma';
    const anchor = captureSourceAnchor({ filePath: 'main.tex', source, from: 6, to: 10, sourceRevision: 3 });
    expect(anchor.selectedText).toBe('beta');
    expect(resolveSourceAnchor(anchor, { source, sourceRevision: 3 })).toMatchObject({
      status: 'resolved', value: { from: 6, to: 10, strategy: 'exact' },
    });
  });

  it('recovers a uniquely moved selection without trusting a stale range', () => {
    const anchor = captureSourceAnchor({ filePath: 'main.tex', source: 'alpha beta gamma', from: 6, to: 10, sourceRevision: 1 });
    expect(resolveSourceAnchor(anchor, { source: 'preface alpha beta gamma', sourceRevision: 2 })).toMatchObject({
      status: 'resolved', value: { from: 14, to: 18, strategy: 'selected-text' },
    });
  });

  it('refuses to reattach duplicate selected text ambiguously', () => {
    const anchor = captureSourceAnchor({ filePath: 'main.tex', source: 'alpha beta gamma', from: 6, to: 10, sourceRevision: 1, contextLength: 0 });
    expect(resolveSourceAnchor(anchor, { source: 'beta and beta', sourceRevision: 2 }).status).toBe('outdated');
  });

  it('falls back to a supplied semantic identity only after textual recovery fails', () => {
    const anchor = captureSourceAnchor({ filePath: 'main.tex', source: 'old title', from: 0, to: 9, semanticId: 'section:intro', semanticKind: 'section' });
    expect(resolveSourceAnchor(anchor, {
      source: 'new title',
      sourceRevision: 4,
      semanticRange: (candidate) => candidate.semanticId === 'section:intro' ? { from: 0, to: 9 } : undefined,
    })).toMatchObject({ status: 'resolved', value: { strategy: 'semantic', from: 0, to: 9 } });
  });
});
