import { describe, expect, it } from 'vitest';
import { appendView, compositionArrays } from './spec-insert';

const layered = JSON.stringify(
  {
    data: { name: 'd' },
    hconcat: [{ layer: [{ mark: 'bar' }] }, { mark: 'point' }],
  },
  null,
  2,
);

describe('compositionArrays', () => {
  it('finds every composition array with its path, including nested', () => {
    const found = compositionArrays(layered);
    const byKey = found.map((c) => ({ key: c.key, path: c.path }));
    expect(byKey).toContainEqual({ key: 'hconcat', path: ['hconcat'] });
    expect(byKey).toContainEqual({ key: 'layer', path: ['hconcat', 0, 'layer'] });
  });

  it('returns offsets that point inside the source text', () => {
    const [first] = compositionArrays(layered);
    expect(layered[first.offset]).toBe('['); // the array node starts at its bracket
  });

  it('is empty for a flat unit spec', () => {
    expect(compositionArrays(JSON.stringify({ mark: 'bar' }))).toEqual([]);
  });
});

describe('appendView', () => {
  it('adds a placeholder view to the array at the given path', () => {
    const spec = { hconcat: [{ mark: 'bar' }] };
    const out = appendView(spec, ['hconcat'])!;
    expect(out.hconcat).toEqual([{ mark: 'bar' }, { mark: 'point', encoding: {} }]);
    expect(spec.hconcat).toHaveLength(1); // input untouched
  });

  it('reaches a nested composition array', () => {
    const spec = { hconcat: [{ layer: [{ mark: 'bar' }] }] };
    const out = appendView(spec, ['hconcat', 0, 'layer'])!;
    const layer = (out.hconcat as { layer: unknown[] }[])[0].layer;
    expect(layer).toHaveLength(2);
  });

  it('returns null when the path is not an array', () => {
    expect(appendView({ mark: 'bar' }, ['layer'])).toBeNull();
  });
});
