/**
 * SET 100d — encode refuses when the prompt has no verifiable residue.
 */
import { describe, expect, it } from 'vitest';
import type { LlmClient } from '../src/core/types';
import { runTier1Job } from '../src/tier1/runner';
import { makeEvalSuiteRunner } from '../src/tier1/testExec';

const ALL_PX_PROMPT = [
  '1. 9999px',
  '2. 1024px',
  '3. 1023px',
  '4. 800px',
  '5. 768px',
  '6. 640px',
].join('\n');

class RefuseEncodeLlm implements Partial<LlmClient> {
  async encodeFeatures(): Promise<never> {
    throw new Error('should not be called');
  }
  async repairFeatures() { return []; }
  async fixStub() { return ''; }
  async generateTests() { return { content: '', parts: { imports: [], cases: [] } }; }
  async fixTestCases() { return { cases: [] }; }
  async generateImplementation() { return []; }
  async repair() { return []; }
}

describe('SET 100d — encode refuse gate', () => {
  it('returns refused before encodeFeatures and emits the refusal line', async () => {
    const events: string[] = [];
    const res = await runTier1Job({
      prompt: ALL_PX_PROMPT,
      rawPrompt: ALL_PX_PROMPT,
      llm: new RefuseEncodeLlm() as unknown as LlmClient,
      runSuite: makeEvalSuiteRunner(),
      onEvent: e => events.push(e.message),
    });

    expect(res.status).toBe('refused');
    expect(res.reason).toBe('prompt-no-verifiable-items');
    expect(res.metrics.encodeRefusedNoResidue).toBe(1);
    expect(events.some(m =>
      m.includes('refused: prompt has no verifiable items — 6 items scanned, 6 capability-fenced, 0 assertable residue'),
    )).toBe(true);
  });
});
