import { describe, expect, it } from 'vitest';
import {
  EXPR_CONSTANT_NAMES,
  EXPR_FUNCTION_NAMES,
  EXPR_SIGNATURES,
  signatureLabel,
} from './vega-expr-catalog';

describe('vega-expr-catalog', () => {
  it('derives a non-empty function set including staple names', () => {
    expect(EXPR_FUNCTION_NAMES.length).toBeGreaterThan(20);
    // Staples a user actually types — if the upstream registry shape changes and
    // these vanish, fail loud rather than silently ship an empty completion list.
    for (const name of ['if', 'datetime', 'test', 'clamp', 'lower', 'length']) {
      expect(EXPR_FUNCTION_NAMES).toContain(name);
    }
  });

  it('derives the constant set including PI and E', () => {
    expect(EXPR_CONSTANT_NAMES).toContain('PI');
    expect(EXPR_CONSTANT_NAMES).toContain('E');
  });

  it('returns names sorted', () => {
    expect([...EXPR_FUNCTION_NAMES]).toEqual([...EXPR_FUNCTION_NAMES].sort());
    expect([...EXPR_CONSTANT_NAMES]).toEqual([...EXPR_CONSTANT_NAMES].sort());
  });

  it('curates only functions the parser actually knows (curated ⊆ derived)', () => {
    const derived = new Set(EXPR_FUNCTION_NAMES);
    for (const name of Object.keys(EXPR_SIGNATURES)) {
      expect(derived.has(name), `${name} is curated but not a real parser function`).toBe(true);
    }
  });

  it('keys each signature by its own name', () => {
    for (const [key, sig] of Object.entries(EXPR_SIGNATURES)) {
      expect(sig.name).toBe(key);
    }
  });

  it('formats a fixed-arity signature label', () => {
    expect(signatureLabel(EXPR_SIGNATURES.if)).toBe('if(test, thenValue, elseValue)');
  });

  it('marks the repeating parameter of a variadic signature', () => {
    expect(signatureLabel(EXPR_SIGNATURES.min)).toBe('min(...values)');
  });

  it('formats a no-argument signature', () => {
    expect(signatureLabel(EXPR_SIGNATURES.now)).toBe('now()');
  });
});
