import { describe, it, expect } from 'vitest';
import * as ts from 'typescript';
import { emitEntityDisplay } from '../helpers-emitter.js';

function assertValidTsx(source: string, label: string): void {
  const result = ts.transpileModule(source, {
    compilerOptions: {
      jsx: ts.JsxEmit.Preserve,
      target: ts.ScriptTarget.ES2022,
      module: ts.ModuleKind.ESNext,
      moduleResolution: ts.ModuleResolutionKind.Bundler,
      strict: true,
    },
    reportDiagnostics: true,
  });
  const errors = result.diagnostics?.filter(d => d.category === ts.DiagnosticCategory.Error) ?? [];
  if (errors.length > 0) {
    const message = errors
      .map(d => ts.flattenDiagnosticMessageText(d.messageText, '\n'))
      .join('\n');
    throw new Error(`${label} failed to parse as TypeScript:\n${message}`);
  }
}

describe('emitEntityDisplay', () => {
  it('produces a module that parses under strict TypeScript', () => {
    assertValidTsx(emitEntityDisplay(), 'entity-display.ts');
  });

  it('exports both getEntityDisplayName and resolveEntityDisplayName', () => {
    const src = emitEntityDisplay();
    expect(src).toMatch(/export function getEntityDisplayName/);
    expect(src).toMatch(/export function resolveEntityDisplayName/);
  });

  it('uses the canonical candidate list in documented order', () => {
    const src = emitEntityDisplay();
    // Order matters: name → title → displayName → label → username → email.
    // The order mirrors @specverse/runtime/views/core/entity-display.
    const candidatesLine = src.match(/const candidates = \[([^\]]+)\]/)?.[1];
    expect(candidatesLine).toBeDefined();
    expect(candidatesLine).toContain("'name'");
    expect(candidatesLine).toContain("'title'");
    expect(candidatesLine).toContain("'displayName'");
    expect(candidatesLine).toContain("'email'");
    // Check relative order
    const order = ['name', 'title', 'displayName', 'label', 'username', 'email'];
    let lastIdx = -1;
    for (const n of order) {
      const idx = candidatesLine!.indexOf(`'${n}'`);
      expect(idx).toBeGreaterThan(lastIdx);
      lastIdx = idx;
    }
  });
});
