import { describe, expect, it } from 'vitest';
import { buildRunLogJson, buildRunLogTxt, formatRelOffset } from '../web/src/exportRunLog';

describe('exportRunLog', () => {
  const base = {
    id: 'abc123',
    ts: '2026-07-26T12:00:00.000Z',
    model: 'local-model',
    prompt: 'build X',
    events: [
      { ts: '2026-07-26T12:00:00.000Z', phase: 'encode', featureId: null, message: 'start' },
      { ts: '2026-07-26T12:01:05.000Z', phase: 'auth', featureId: 'F1', message: '1/2 passing' },
    ],
    problems: ['F1: remaining'],
    metrics: { elapsedMs: 65000, llmCalls: 2 },
    epochs: [{ ts: '2026-07-26T12:00:00.000Z', model: 'local-model', prompt: 'build X' }],
    contractVersion: 'V1.11+deadbeefdeadbeef',
    vaultVersion: '0.1.12',
    corpusVersion: 'V1.11',
  };

  it('formats relative offsets as +MmSSs', () => {
    expect(formatRelOffset(base.ts, '2026-07-26T12:01:05.000Z')).toBe('+1m05s');
    expect(formatRelOffset(base.ts, '2026-07-26T12:00:09.000Z')).toBe('+9s');
  });

  it('txt contains header, every event, problems, metrics', () => {
    const txt = buildRunLogTxt(base);
    expect(txt).toContain('run id: abc123');
    expect(txt).toContain('contract: V1.11+deadbeefdeadbeef');
    expect(txt).toContain('vault: 0.1.12');
    expect(txt).toContain('[+0s] [encode] [—] start');
    expect(txt).toContain('[+1m05s] [auth] [F1] 1/2 passing');
    expect(txt).toContain('F1: remaining');
    expect(txt).toContain('"llmCalls": 2');
    expect(txt).toContain('--- evidence ---');
  });

  it('json shape matches the machine-readable contract', () => {
    const j = JSON.parse(buildRunLogJson(base)) as Record<string, unknown>;
    expect(j.id).toBe('abc123');
    expect(j.prompt).toBe('build X');
    expect(Array.isArray(j.events)).toBe(true);
    expect(Array.isArray(j.problems)).toBe(true);
    expect(Array.isArray(j.evidence)).toBe(true);
    expect(j.metrics).toEqual(base.metrics);
    expect(j.epochs).toEqual(base.epochs);
    expect(j.model).toBe('local-model');
  });

  it('SET 34 — evidence section includes seam-dump from attribution-miss events', () => {
    const withMiss = {
      ...base,
      events: [
        ...base.events,
        {
          ts: '2026-07-26T12:01:10.000Z',
          phase: 'rha',
          featureId: null,
          message: 'attribution-miss: program crashed, 2/2 probes clean — probe set diff: none',
        },
        {
          ts: '2026-07-26T12:01:10.000Z',
          phase: 'rha',
          featureId: null,
          message: 'seam-dump: src/a.ts ⨝ src/b.ts · «join»',
        },
      ],
    };
    const txt = buildRunLogTxt(withMiss);
    expect(txt).toContain('--- evidence ---');
    expect(txt).toContain('seam-dump: src/a.ts ⨝ src/b.ts');
    expect(txt).toContain('attribution-miss:');
  });
});
