import { describe, expect, test } from 'vitest';
import { compile } from 'vega-lite';
import { CHART_EXAMPLES, exampleSpecText } from './examples';
import { SAMPLE_SPEC, VEGA_LITE_SCHEMA_URL } from './snippet';

describe('chart examples', () => {
  test('the gallery is non-empty and ids are unique', () => {
    expect(CHART_EXAMPLES.length).toBeGreaterThan(0);
    const ids = CHART_EXAMPLES.map((e) => e.id);
    expect(new Set(ids).size).toBe(ids.length);
  });

  test('the bar example reuses the blank-snippet template (one source of truth)', () => {
    const bar = CHART_EXAMPLES.find((e) => e.id === 'bar');
    expect(bar?.spec).toBe(SAMPLE_SPEC);
  });

  // The whole promise of the gallery is that every card renders. A spec that
  // doesn't compile would render to an error on first paint — so each example
  // must be valid, self-contained Vega-Lite.
  describe.each(CHART_EXAMPLES.map((e) => [e.id, e] as const))('example: %s', (_id, example) => {
    test('has a name and a one-line description', () => {
      expect(example.name.trim()).not.toBe('');
      expect(example.description.trim()).not.toBe('');
    });

    test('pins the bundled Vega-Lite schema', () => {
      expect(example.spec.$schema).toBe(VEGA_LITE_SCHEMA_URL);
    });

    test('carries inline data only (no named/url reference, no dataset coupling)', () => {
      const data = example.spec.data as { values?: unknown[]; name?: string; url?: string };
      expect(Array.isArray(data?.values)).toBe(true);
      expect(data.values?.length ?? 0).toBeGreaterThan(0);
      expect(data.name).toBeUndefined();
      expect(data.url).toBeUndefined();
    });

    test('compiles as valid Vega-Lite', () => {
      // compile() is pure (produces a Vega spec, no DOM/render); it throws on an
      // invalid Vega-Lite spec, which is exactly the failure we want to catch.
      expect(() => compile(example.spec as unknown as Parameters<typeof compile>[0])).not.toThrow();
    });

    test('serializes to JSON text that round-trips to the spec', () => {
      expect(JSON.parse(exampleSpecText(example))).toEqual(example.spec);
    });
  });
});
