import assert from 'node:assert/strict';
import { test } from 'node:test';

import { bestAlternate } from '../grade';
import { evidence, f1Exact, score, type Episode } from '../score';

/**
 * Vectors the page's copy relies on, checked against the browser scorer. The
 * cross-language digest proves the port matches the Python; these prove the
 * sentences on the Reward tab match the port.
 */

const base: Episode = {
  label: 'benign',
  planted: [['kyc.expected_monthly_cash'], ['kyc.expected_monthly_cash', 'kyc.business_type']],
  disposition: 'close',
  cites: ['kyc.expected_monthly_cash'],
  minutes_spent: 33,
  reference_minutes: 33,
  turns_spent: 1,
  rejected: 0,
  truncated: false,
};

test('a correct, well-cited close at the reference scores 1.0 everywhere', () => {
  assert.deepEqual(score(base), { caught: 1, hours: 1, evidence: 1 });
});

test('a missed escalation scores exactly 0.000 on every component', () => {
  assert.deepEqual(score({ ...base, label: 'suspicious', planted: [['T-1', 'T-2']] }), {
    caught: 0,
    hours: 0,
    evidence: 0,
  });
});

test('a false escalation earns the credit on caught and nothing else', () => {
  assert.deepEqual(score({ ...base, disposition: 'escalate', cites: ['T-1'] }), {
    caught: 0.5,
    hours: 0,
    evidence: 0,
  });
});

test('no disposition is zero, not null; a truncated run is null, not zero', () => {
  assert.deepEqual(score({ ...base, disposition: null, cites: [] }), { caught: 0, hours: 0, evidence: 0 });
  assert.deepEqual(score({ ...base, truncated: true }), { caught: null, hours: null, evidence: null });
});

test('hours is capped at one and null without a reference', () => {
  assert.equal(score({ ...base, minutes_spent: 20 }).hours, 1);
  assert.equal(score({ ...base, minutes_spent: 66 }).hours, 0.5);
  assert.equal(score({ ...base, reference_minutes: null }).hours, null);
});

test('precision bites: one planted id among eight cited is F1 0.22', () => {
  const cites = ['kyc.expected_monthly_cash', 'T-1', 'T-2', 'T-3', 'T-4', 'T-5', 'T-6', 'T-7'];
  assert.deepEqual(f1Exact(cites, ['kyc.expected_monthly_cash']), [2, 9]);
  assert.equal(evidence({ ...base, cites }), 2 / 9);
});

test('the best alternate is scored, and the board can recover which one', () => {
  const cites = ['kyc.expected_monthly_cash', 'kyc.business_type'];
  assert.deepEqual(bestAlternate(cites, base.planted), base.planted[1]);
  assert.equal(evidence({ ...base, cites }), 1);
  // A tie goes to the first alternate, as the scorer's strict `>` does.
  assert.deepEqual(bestAlternate(['T-9'], base.planted), base.planted[0]);
});

test('planted ids are matched exact-case and an unshown id simply misses', () => {
  assert.equal(evidence({ ...base, cites: ['KYC.EXPECTED_MONTHLY_CASH'] }), 0);
  assert.equal(evidence({ ...base, cites: ['doc.probate_letter', 'kyc.expected_monthly_cash'] }), 2 / 3);
});
