/**
 * SET 37 — Stream C: superbuffer pages (37e), ideation helpers (37f),
 * failure-stack primitives (37h/37a). No runner wiring.
 */
import { describe, expect, it } from 'vitest';
import type { FeatureNode, FeatureSpec } from '../src/core/types';
import { CONCEPT_SYSTEM, conceptUser } from '../src/core/prompts';
import {
  assembleSuperbuffer,
  encodeFeatureSpecPage,
  sanitizeConceptPage,
  STAGE_PAGE_POLICY,
  formatConceptDrawEvent,
  CONCEPT_DRAW_TEMP,
} from '../src/tier1/superbuffer';
import {
  emptyFailureStack,
  shouldDrawInPlace,
  shouldSkipFailureStack,
  pushDeferredFailure,
  formatStackDropReason,
  formatRelayReenter,
  FAILURE_STACK_INSTANCE_CAP,
  mayReenter,
  rememberWorld,
  worldDelta,
} from '../src/tier1/failureStack';
import {
  freshRelayBatchParams,
  batchParamsIdentical,
  defaultBatchParams,
} from '../src/tier1/permutation';
import {
  formatConceptEfficacy,
  formatPermanentDeferral,
  formatContinueProjectReplanNote,
  formatParsePoisonIncidents,
} from '../src/tier1/reportEvidence';

function feature(partial: Partial<FeatureNode> & { id: string }): FeatureNode {
  return {
    name: partial.name ?? partial.id,
    description: partial.description ?? 'literal feature description from Parse',
    parentId: null,
    deps: partial.deps ?? [],
    files: partial.files ?? [`src/${partial.id.toLowerCase()}.ts`],
    testFile: partial.testFile ?? `tests/${partial.id.toLowerCase()}.test.ts`,
    edgeCases: partial.edgeCases ?? ['roundtrip'],
    envVars: [],
    exports: partial.exports ?? [{ file: `src/${partial.id.toLowerCase()}.ts`, symbol: 'fn' }],
    stubs: partial.stubs ?? [{
      path: `src/${partial.id.toLowerCase()}.ts`,
      content: 'export function fn(x: string): string { throw new Error("stub: not implemented"); }\n',
    }],
    ...partial,
  };
}

describe('SET 37e superbuffer pages', () => {
  it('packs LITERAL encoded feature text into the spec page (not discarded)', () => {
    const f = feature({
      id: 'F1',
      name: 'Codec',
      description: 'encode and decode payloads with roundtrip fidelity',
      edgeCases: ['roundtrip', 'empty'],
    });
    const spec: FeatureSpec = { title: 'T', prompt: 'codec roundtrip', features: [f] };
    const literal = encodeFeatureSpecPage(f, spec);
    expect(literal).toContain('encode and decode payloads');
    expect(literal).toContain('roundtrip');
    expect(literal).toContain('Feature F1: Codec');

    const fill = assembleSuperbuffer({
      spec, feature: f, parts: null, stubs: f.stubs, lessons: [],
      siblingParts: new Map(), target: 'roundtrip', stage: 'fill',
      signature: { name: 'fn', params: ['string'], returnType: 'string' },
    });
    expect(fill.pages.spec).toBeDefined();
    expect(fill.pages.spec!.text).toContain('encode and decode payloads');
    expect(fill.promptBlock).toContain('encode and decode payloads');
    expect(fill.logLine).toMatch(/^superbuffer: assembled \(/);
    expect(fill.logLine).toMatch(/pages \[.*spec:\d+/);
    expect(fill.stage).toBe('fill');
  });

  it('exposes stage policy pages: fill / build / repair', () => {
    // SET 45b — substrate page high-priority on fill/repair (omitted when empty).
    // SET 75 — the watcher's union page rides every stage (advisory).
    // SET 82 — CONTRACT FIRST, advisory LAST: a small model reads what it is
    // given first, so the union page must never precede the spec.
    expect(STAGE_PAGE_POLICY.fill).toEqual([
      'substrate', 'spec', 'contract', 'corpus', 'siblings', 'union',
    ]);
    expect(STAGE_PAGE_POLICY.build).toEqual([
      'spec', 'contract', 'constants', 'frozen', 'concept', 'corpus', 'union',
    ]);
    // SET 64c/64d — exhibit + trace pack early on repair (small, position-bearing).
    // SET 75 — `ledger` (this node's causal trail) is repair-stage evidence.
    expect(STAGE_PAGE_POLICY.repair).toEqual([
      'substrate', 'finding-evidence', 'exhibit', 'trace', 'contract', 'constants', 'ledger', 'union', 'frozen', 'lessons', 'concept',
    ]);

    const f = feature({ id: 'F2' });
    const spec: FeatureSpec = { title: 'T', prompt: 'p', features: [f] };
    const parts = {
      imports: [],
      cases: [{ name: 'roundtrip', kind: 'edge' as const, body: "expect(fn('a')).toBe('a');" }],
    };
    const build = assembleSuperbuffer({
      spec, feature: f, parts, stubs: f.stubs, lessons: [],
      siblingParts: new Map(), target: 'fn', stage: 'build',
      conceptText: 'Ship as a pure transform with explicit edge tables.',
    });
    expect(Object.keys(build.pages)).toEqual(
      expect.arrayContaining(['spec', 'contract', 'frozen', 'concept']),
    );
    expect(build.promptBlock).toContain('CONTEXT ONLY');
    expect(build.pages.concept!.text).not.toMatch(/```/);
    expect(sanitizeConceptPage('```ts\nexport function fn(){}\n```')).not.toContain('export function');

    const repair = assembleSuperbuffer({
      spec, feature: f, parts, stubs: f.stubs,
      lessons: [{
        classKey: 'assertion|eq',
        idiom: 'align expected',
        resolution: 'fix expected',
        ts: new Date().toISOString(),
      }],
      siblingParts: new Map(), target: 'assertion|eq', stage: 'repair',
      findingEvidence: 'Expected "a" but got "b"',
      conceptText: 'Keep invariants central.',
    });
    expect(repair.pages['finding-evidence']).toBeDefined();
    expect(repair.pages.lessons).toBeDefined();
    expect(repair.logLine).toContain('stage=repair');
  });
});

describe('SET 37f ideation entropy helpers', () => {
  it('concept prompts forbid code; sanitize strips fences', () => {
    expect(CONCEPT_SYSTEM).toMatch(/Do NOT emit implementation code/i);
    expect(CONCEPT_DRAW_TEMP).toBeGreaterThan(1);
    const page = encodeFeatureSpecPage(feature({ id: 'F1' }));
    const user = conceptUser(page, { id: 'F1', name: 'Codec' });
    expect(user).toContain('In 3 sentences: approach, pitfalls, data shapes');
    expect(user).toContain('No code');
    const dirty = 'Approach: pure fn.\n```ts\nexport function fn(){}\n```\nDone.';
    const clean = sanitizeConceptPage(dirty);
    expect(clean).not.toContain('export function');
    expect(clean).toContain('concept is prose context only');
    expect(formatConceptDrawEvent('F1', 120)).toBe(
      'concept draw: F1 (120 chars, context only)',
    );
  });

  it('formats concept efficacy split for report', () => {
    const line = formatConceptEfficacy(
      { cases: 10, filled: 8 },
      { cases: 4, filled: 1 },
    );
    expect(line).toMatch(/concept page/);
    expect(line).toContain('80%');
    expect(line).toContain('25%');
  });
});

describe('SET 37h / 37a failure stack primitives', () => {
  it('mechanical in-place; model from end; empty-draw skips stack', () => {
    expect(shouldDrawInPlace('mechanical')).toBe(true);
    expect(shouldDrawInPlace('model')).toBe(false);
    expect(shouldSkipFailureStack('empty-draw', '')).toBe(true);
    expect(shouldSkipFailureStack('parse', '')).toBe(true);
    expect(shouldSkipFailureStack('parse', 'expect(x')).toBe(false);
  });

  it('caps instances at 3; drop reason names both stages; relay formatter', () => {
    let state = emptyFailureStack();
    for (let i = 0; i < FAILURE_STACK_INSTANCE_CAP; i++) {
      const r = pushDeferredFailure(state, {
        featureId: 'F3',
        caseName: 'roundtrip',
        kind: 'parse',
        brokenDraw: 'expect(fn(',
        parseError: 'Unexpected token',
        snippet: 'expect(fn(',
        position: { line: 1, col: 10 },
      });
      expect(r.pushed).toBeTruthy();
      state = r.state;
    }
    const over = pushDeferredFailure(state, {
      featureId: 'F3',
      caseName: 'roundtrip',
      kind: 'parse',
      brokenDraw: 'expect(fn(',
      parseError: 'Unexpected token',
      snippet: 'expect(fn(',
    });
    expect(over.pushed).toBeNull();
    expect(over.reason).toMatch(/instance cap/);

    expect(formatStackDropReason()).toBe(
      'dropped after parse-loop (1 oracle pass, 1 warm targeted redraw)',
    );
    expect(formatRelayReenter({
      featureId: 'F3', instance: 2, healsDelta: 2, lessonsDelta: 3,
    })).toBe(
      'relay: F3 re-entering (instance 2/3, world changed: +2 heals, +3 lessons)',
    );
  });

  it('changed-world precondition + fresh entropy never byte-identical', () => {
    let state = emptyFailureStack();
    const prev = { frozenCount: 1, lessonCount: 2, siblingCaseCount: 3 };
    const now = { frozenCount: 3, lessonCount: 5, siblingCaseCount: 3 };
    state = rememberWorld(state, 'F3|x', prev);
    expect(mayReenter(state, 'F3|x', prev).ok).toBe(false);
    expect(mayReenter(state, 'F3|x', now).ok).toBe(true);
    expect(worldDelta(prev, now)).toEqual({ heals: 2, lessons: 3, siblings: 0 });

    const a = defaultBatchParams();
    const b = freshRelayBatchParams(a, { salt: 42 });
    const c = freshRelayBatchParams(b, { salt: 99 });
    expect(batchParamsIdentical(a, b)).toBe(false);
    expect(batchParamsIdentical(b, c)).toBe(false);
  });
});

describe('SET 37g / 38c report strings', () => {
  it('formats permanent deferral, continue-project note, parse-poison line', () => {
    expect(formatPermanentDeferral('mock-API')).toBe(
      'excluded — requires mock-API; not testable in this runtime',
    );
    expect(formatContinueProjectReplanNote(3)).toMatch(/replan 3 previously-dropped/);
    expect(formatParsePoisonIncidents(2, 5)).toBe(
      'parse-poison incidents: 2 (prior run: 5)',
    );
  });
});
