import type { H6Breakdown, H6Report } from './h6-report.js'; const escapeHtml = (value: unknown): string => String(value ?? '') .replaceAll('&', '&') .replaceAll('<', '<') .replaceAll('>', '>') .replaceAll('"', '"') .replaceAll("'", '''); const number = (value: number): string => new Intl.NumberFormat('en-US').format(value); const money = (value: number): string => `$${value.toFixed(6)}`; function breakdownRows(rows: H6Breakdown[]): string { if (rows.length === 0) return 'No records in the selected scope.'; return rows.map((row) => ` ${escapeHtml(row.key)}${number(row.runs)}${number(row.failures)} ${number(row.latency_avg_ms)} ms${number(row.tokens)}${money(row.cost_usd)} `).join(''); } export function renderH6ReportHtml(report: H6Report): string { const verdictClass = report.verdict === 'pass' ? 'pass' : report.verdict === 'fail' ? 'fail' : report.verdict === 'attention' ? 'attention' : 'neutral'; const scope = [ report.scope.project ? `Project: ${report.scope.project}` : 'All projects', report.scope.run ? `Run: ${report.scope.run}` : 'All runs', report.scope.from ? `From: ${report.scope.from}` : null, report.scope.to ? `To: ${report.scope.to}` : null, ].filter((value): value is string => Boolean(value)); const findings = report.findings.length ? report.findings.map((finding) => `
  • ${escapeHtml(finding.code)}${escapeHtml(finding.message)}
  • `).join('') : '
  • NO_FINDINGSNo threshold breach was detected in this scope.
  • '; const sourceRows = report.evidence_sources.map((source) => ` ${escapeHtml(source.source)}${source.present ? 'present' : 'missing'}${source.stale ? 'stale' : 'fresh'} ${source.age_s === null ? '—' : `${number(source.age_s)} s`}${number(source.records)}${escapeHtml(source.path)} `).join(''); const warnings = report.data_quality.warnings.length ? `` : '

    No data-quality warning.

    '; return ` ${escapeHtml(report.title)} · ${escapeHtml(report.report_id)}
    CASAN assurance dossier · contract v${report.schema_version}

    ${escapeHtml(report.title)}

    ${scope.map((item) => `${escapeHtml(item)}`).join('')}
    ${escapeHtml(report.verdict)}
    Generated ${escapeHtml(report.generated_at)} · ${escapeHtml(report.report_id)} · Freshness ${escapeHtml(report.freshness.status)}
    Governed runs${number(report.summary.runs)}
    Failure rate${report.summary.failure_rate_pct}%
    P95 latency${number(report.summary.latency_ms.p95)} ms
    Provider tokens${number(report.summary.tokens.provider_total)}
    Actual provider cost${money(report.summary.cost_usd.provider_actual)}
    Estimated cost${money(report.summary.cost_usd.estimated)}
    Alerts${number(report.summary.alerts)}
    Retries${number(report.summary.retries)}

    Verdict findings

    Evidence freshness

    ${sourceRows}
    SourcePresenceStateAgeRecordsPath

    Step breakdown

    ${breakdownRows(report.details.by_step)}
    StepRunsFailuresAvg latencyTokensCost

    Provider/model breakdown

    ${breakdownRows(report.details.by_provider)}
    Provider · modelCallsFailuresAvg latencyTokensCost

    Data quality · ${escapeHtml(report.data_quality.status)}

    ${warnings}
    `; }