import { isApiErrorV1 } from './simulation-contract.ts'; export type SimulationApiChoice = { id: string; label: string }; function scalar(value: unknown): string { return typeof value === 'string' || (typeof value === 'number' && Number.isFinite(value)) ? String(value) : ''; } /** Parse API bodies without leaking JSON parser errors into the public form. */ export async function readSimulationApiJson( response: Response, ): Promise { try { return await response.json(); } catch { return null; } } /** Prefer field validation details, falling back to the shared API message. */ export function simulationApiErrorMessage(value: unknown): string | undefined { if (!isApiErrorV1(value)) return undefined; const validationMessages = Object.values(value.errors ?? {}).flat(); return validationMessages.length ? validationMessages.join(' ') : value.message; } /** Keep snapshot field errors attached to their original form fields. */ export function simulationApiFieldErrors( value: unknown, ): Record { if (!isApiErrorV1(value)) return {}; const fields: Record = {}; for (const [path, messages] of Object.entries(value.errors ?? {})) { const key = path .replace(/^(economic_snapshot|personal_snapshot)\./, '') .split('.')[0]; if (/^[a-z][a-z0-9_]*$/.test(key) && messages.length) fields[key] = messages.join(' '); } return fields; } /** Explain a failed status check without implying the accepted job was lost. */ export function simulationPollingFailureMessage(value: unknown): string { return ( simulationApiErrorMessage(value) ?? 'O cenário foi recebido, mas não foi possível confirmar o estado do cálculo. Consulte o histórico antes de tentar novamente.' ); } /** Validate and normalize the public reference catalog envelope. */ export function simulationCatalogChoices( value: unknown, ): SimulationApiChoice[] { if ( !value || typeof value !== 'object' || Array.isArray(value) || !Array.isArray((value as Record).data) ) throw new Error('O servidor devolveu opções com formato inválido.'); return (value as { data: unknown[] }).data.flatMap((row) => { if (!row || typeof row !== 'object' || Array.isArray(row)) return []; const record = row as Record; const choice = { id: scalar(record.id ?? record.value), label: scalar(record.label ?? record.name), }; return choice.id && choice.label ? [choice] : []; }); }