/**
 * SET 17 — Superbuffer assembly scoring + metrics.
 */
import { describe, expect, it } from 'vitest';
import type { FeatureSpec } from '../src/core/types';
import {
  assembleSuperbuffer,
  freeformPatternKey,
  nameTokenOverlap,
  shouldProposeCladePromotion,
  signatureSimilarity,
  SUPERBUFFER_TOKEN_CAP,
} from '../src/tier1/superbuffer';
import type { IRParts } from '../src/core/irScaffold';
import { TESTGEN_TEMPLATES } from '../src/tier1/testgenOracle.generated';

const feature = {
  id: 'F1',
  name: 'slug',
  description: 'slugify',
  parentId: null,
  deps: [],
  files: ['src/slug.ts'],
  testFile: 'tests/f1.test.ts',
  edgeCases: ['empty'],
  envVars: [],
  exports: [{ file: 'src/slug.ts', symbol: 'slugify' }],
  stubs: [{
    path: 'src/slug.ts',
    content: 'export function slugify(s: string): string { throw new Error("stub"); }\n',
  }],
};

const spec = { title: 'Slug', prompt: 'slug', features: [feature] } as unknown as FeatureSpec;

const parts: IRParts = {
  imports: [{ from: 'src/slug', symbols: ['slugify'] }],
  cases: [
    {
      name: 'slugify', kind: 'behavior',
      body: "expect(slugify('Hello')).toBe('hello');",
      clade: { branch: 'freeform', family: 'freeform', bindings: { symbol: 'slugify' } },
    },
  ],
};

describe('SET 17 superbuffer scoring', () => {
  it('scores signature similarity by arity/types/name overlap', () => {
    const unary = TESTGEN_TEMPLATES.find(t => t.paramCount === 1 && t.paramTypes[0] === 'string');
    expect(unary).toBeTruthy();
    const hi = signatureSimilarity(
      { name: 'slugify', params: ['string'], returnType: 'string' },
      unary!,
      'slugify',
    );
    const lo = signatureSimilarity(
      { name: 'add', params: ['number', 'number'], returnType: 'number' },
      unary!,
      'add',
    );
    expect(hi).toBeGreaterThan(lo);
    expect(nameTokenOverlap('slugify-empty', 'empty-input')).toBeGreaterThan(0);
  });

  it('assembles a capped buffer and logs template/lesson/sibling counts', () => {
    const siblingParts = new Map<string, IRParts>([
      ['F2', {
        imports: [],
        cases: [{
          name: 'trim-roundtrip', kind: 'edge',
          body: "expect(trim(trim('x'))).toBe(trim('x'));",
          clade: { branch: 'algebraic', family: 'roundtrip', bindings: {} },
        }],
      }],
    ]);
    const assembly = assembleSuperbuffer({
      spec,
      feature: feature as FeatureSpec['features'][0],
      parts,
      stubs: feature.stubs,
      lessons: [
        { classKey: 'runtime|nullread|x', idiom: 'null guard', resolution: 'early return', ts: '' },
        { classKey: 'assertion|toBe', idiom: 'toBe', resolution: 'check ops', ts: '' },
      ],
      siblingParts,
      target: 'freeform|slugify',
      signature: { name: 'slugify', params: ['string'], returnType: 'string' },
    });
    // SET 34f — optional `[family, …]` provenance after template/lesson counts.
    expect(assembly.logLine).toMatch(
      /^superbuffer: assembled \(\d+ stubs, \d+ frozen, \d+ templates(?: \[[^\]]*\])?, \d+ lessons(?: \[[^\]]*\])?, \d+ siblings(?:; pages \[[^\]]*\])?\)(?: stage=\w+)? for "/,
    );
    expect(assembly.logLine).toMatch(/^superbuffer: assembled \((?!0 stubs)/);
    expect(assembly.approxTokens).toBeLessThanOrEqual(SUPERBUFFER_TOKEN_CAP);
    expect(assembly.promptBlock).toContain('Superbuffer');
    expect(assembly.stubSignatures.some(s => s.includes('slugify'))).toBe(true);
  });

  it('proposes clade promotion at ≥3 wins', () => {
    expect(shouldProposeCladePromotion(2)).toBe(false);
    expect(shouldProposeCladePromotion(3)).toBe(true);
    expect(freeformPatternKey({ classKey: 'runtime|weird|x' })).toBe('class:runtime|weird');
  });
});
