/**
 * 探针：确认前端判定器把「无判定规则」和「待判定」分开，且前者不计入合格率与报告结论。
 *
 * 背景：报告里常有「试样质量 m」「称量瓶 m0」这类只供公式取数的过程参数，它们没有规格、
 * 也没有规则，属于「无从判定」。若照常算进分母，一份本来全合格的报告会被这些行压成「待判定」。
 *
 * 只读，不改代码、不碰数据库。用法：npx tsx .qc-conformance/verify-undecidable.ts
 */
import type { ReportContextItem } from '../src/components/quality/engine/context';

import { createContext } from '../src/components/quality/engine/context';
import { evaluateReport } from '../src/components/quality/engine/report-evaluator';

type Item = Partial<ReportContextItem> & { itemName: string };

const base = { reportNo: 'QC-2026-0001', reportName: '来料检验报告' };

function evaluate(items: Item[], rules: unknown[] = []) {
  const context = createContext({ report: base, inspectionItems: items as ReportContextItem[] });
  return evaluateReport(context, rules as never);
}

/** 一条带规格上下限的项，用来当「正常可判定」的对照组 */
const withLimits = (name: string, actual: string, upper: number, lower: number): Item => ({
  itemName: name,
  actualValue: actual,
  upperLimit: upper,
  lowerLimit: lower,
});

/** 一条只供公式取数的过程参数：既没有上下限、也没有自带结果 */
const processParam = (name: string, actual: string): Item => ({ itemName: name, actualValue: actual });

const failures: string[] = [];

function expect(label: string, actual: unknown, wanted: unknown) {
  const ok = actual === wanted;
  if (!ok) {
    failures.push(`${label}：期望 ${JSON.stringify(wanted)}，实际 ${JSON.stringify(actual)}`);
  }
  // eslint-disable-next-line no-console
  console.log(`${ok ? '  ok  ' : ' FAIL '} ${label} = ${JSON.stringify(actual)}`);
}

// --------- 场景 1：过程参数 + 可判定项混排，报告仍然应当给出「合格」
{
  // eslint-disable-next-line no-console
  console.log('\n===== 场景 1：试样质量 m（过程参数）不该把全合格的报告压成待判定 =====');
  const outcome = evaluate([withLimits('长度', '10.2', 10.5, 9.5), processParam('试样质量 m', '50.2')]);
  const report = outcome.context.report;
  const items = outcome.context.inspectionItems;

  expect('长度.resultText', items[0].resultText, '合格');
  expect('试样质量 m.resultText', items[1].resultText, '无判定规则');
  expect('试样质量 m.result', items[1].result, '');
  expect('report.total（真实项数）', report.total, 2);
  expect('report.passCount', report.passCount, 1);
  expect('report.failCount', report.failCount, 0);
  expect('report.passRate（分母只算可判定项）', report.passRate, '100.00%');
  expect('report.result', report.result, 'PASS');
  expect('report.conclusion', report.conclusion, '合格');
  // eslint-disable-next-line no-console
  console.log(`  问题清单：${JSON.stringify(outcome.errors)}`);
}

// --------- 场景 2：一项都判不了时不硬给结论
{
  // eslint-disable-next-line no-console
  console.log('\n===== 场景 2：全部是无判定规则项，合格率留空、不给结论 =====');
  const outcome = evaluate([processParam('试样质量 m', '50.2'), processParam('称量瓶 m0', '28.7')]);
  const report = outcome.context.report;

  expect('report.total', report.total, 2);
  expect('report.passRate', report.passRate, '');
  expect('report.result', report.result, '');
  expect('report.conclusion', report.conclusion, '待判定');
}

// --------- 场景 3：待判定（规则跑挂）仍留在分母里，仍压住合格结论
{
  // eslint-disable-next-line no-console
  console.log('\n===== 场景 3：待判定（规则跑挂）仍计入分母、仍不给合格结论 =====');
  const outcome = evaluate(
    [withLimits('长度', '10.2', 10.5, 9.5), withLimits('宽度', '4.9', 5.0, 4.0), processParam('外观', '无划痕')],
    // 「无划痕」不是数字，ABS 在它身上算不出来 → 该项待判定
    [{ id: 'r1', name: '实测值可算', scope: 'item', expression: 'ABS(item.actualValue) >= 0' }],
  );
  const report = outcome.context.report;
  const items = outcome.context.inspectionItems;

  expect('长度.resultText', items[0].resultText, '合格');
  expect('外观.resultText', items[2].resultText, '待判定');
  expect('report.total', report.total, 3);
  expect('report.passCount', report.passCount, 2);
  expect('report.passRate（待判定项留在分母里）', report.passRate, '66.67%');
  expect('report.result（没验过不给合格）', report.result, '');
  expect('report.conclusion', report.conclusion, '待判定');
}

// eslint-disable-next-line no-console
console.log(
  failures.length === 0
    ? '\n全部通过：无判定规则不计入分母与结论，待判定仍计入分母并压住合格结论。'
    : `\n有 ${failures.length} 处不符：\n${failures.map((line) => `  - ${line}`).join('\n')}`,
);
process.exitCode = failures.length === 0 ? 0 : 1;
