import { describe, expect, it } from 'vitest';
import { changedLines } from './spec-diff';

const set = (...n: number[]) => new Set(n);

describe('changedLines', () => {
  it('marks nothing when the text is identical', () => {
    const text = '{\n  "mark": "bar"\n}';
    expect(changedLines(text, text)).toEqual(new Set());
  });

  it('marks a line inserted in the middle', () => {
    const prev = 'a\nb\nc';
    const next = 'a\nb\nNEW\nc';
    expect(changedLines(prev, next)).toEqual(set(2));
  });

  it('marks a replaced line (old dropped, new flagged)', () => {
    const prev = 'a\nb\nc';
    const next = 'a\nB!\nc';
    expect(changedLines(prev, next)).toEqual(set(1));
  });

  it('flags a genuinely-new duplicate line, not the pre-existing one', () => {
    // Vega specs repeat lines; a naive membership test would mishighlight here.
    const prev = '"type": "quantitative"';
    const next = '"type": "quantitative"\n"type": "quantitative"';
    expect(changedLines(prev, next).size).toBe(1);
  });

  it('marks an appended block of lines', () => {
    const prev = '{\n  "mark": "bar"\n}';
    const next = '{\n  "mark": "bar",\n  "params": [\n    { "name": "step" }\n  ]\n}';
    // The closing brace line is unchanged content but shifts position; the params
    // lines and the comma-suffixed mark line are the changes.
    const changed = changedLines(prev, next);
    expect(changed.has(2)).toBe(true); // "params": [
    expect(changed.has(3)).toBe(true); // { "name": "step" }
    expect(changed.has(0)).toBe(false); // opening brace unchanged
  });

  it('treats an empty previous text as an all-new baseline', () => {
    expect(changedLines('', 'a\nb')).toEqual(set(0, 1));
  });

  it('marks everything when all lines change', () => {
    expect(changedLines('a\nb', 'x\ny')).toEqual(set(0, 1));
  });
});
