import type { DemographicAnalysis } from '../components/demographic-evidence'; type Series = DemographicAnalysis['territories'][number]['series'][number]; type Row = Series['values'][number]; const children = ['0-4', '5-9', '10-14']; const adults = [ '15-19', '20-24', '25-29', '30-34', '35-39', '40-44', '45-49', '50-54', '55-59', '60-64', ]; // Display-only derivation. Original decimals, persisted evidence and fiscal calculations are untouched. function numeric(row: Row | undefined): number | null { if ( !row || !['pessoas', 'persons'].includes(row.unit) || !/^\d+(\.\d+)?$/.test(row.value) ) return null; const n = Number(row.value); return Number.isFinite(n) && n <= Number.MAX_SAFE_INTEGER ? n : null; } function one(rows: Row[], age: string, residence = 'all'): Row | undefined { const found = rows.filter( (r) => r.indicator === 'population' && r.age_group === age && r.residence === residence, ); return found.length === 1 ? found[0] : undefined; } export const populationLabel = (n: number | null) => n === null ? 'Sem dados' : new Intl.NumberFormat('pt-MZ', { maximumFractionDigits: 0 }).format( n, ); export const percentageLabel = (n: number | null) => n === null ? 'Sem dados' : new Intl.NumberFormat('pt-MZ', { maximumFractionDigits: 1, minimumFractionDigits: 1, }).format(n) + '%'; export function demographicReading(series: Series, start: number, end: number) { function year(year: number) { const rows = series.values.filter((r) => r.year === year); const totalRow = one(rows, 'all'); const total = numeric(totalRow); const compatible = (r: Row | undefined) => r && totalRow && r.unit === totalRow.unit && r.data_kind === totalRow.data_kind; const part = (age: string, residence = 'all') => { const r = one(rows, age, residence); return compatible(r) ? numeric(r) : null; }; const sum = (ages: string[]) => { const values = ages.map((age) => part(age)); return values.every((v) => v !== null) ? values.reduce((a, v) => a + (v ?? 0), 0) : null; }; const share = (n: number | null) => total !== null && total > 0 && n !== null && n <= total ? (n / total) * 100 : null; const urban = part('all', 'urban'), rural = part('all', 'rural'); const residenceReconciled = total !== null && urban !== null && rural !== null && Math.abs(urban + rural - total) <= Math.max(0.000001, total * 1e-10); const under15 = sum(children), age15to64 = sum(adults); return { year, total, kind: totalRow?.data_kind, unit: totalRow?.unit, urban, rural, urbanShare: residenceReconciled ? share(urban) : null, ruralShare: residenceReconciled ? share(rural) : null, under15, under15Share: share(under15), age15to64, age15to64Share: share(age15to64), }; } const first = year(start), last = year(end); const comparable = end > start && first.total !== null && last.total !== null && first.kind === last.kind && first.unit === last.unit; const delta = comparable ? last.total! - first.total! : null; const growth = delta !== null && first.total! > 0 ? (delta / first.total!) * 100 : null; return { first, last, delta, growth, years: Array.from({ length: end - start + 1 }, (_, i) => year(start + i), ), }; }