import type { DashboardReportCountingRow, DashboardReportFeedInRow, DashboardReportFeedOutRow, DashboardReportFeedUseRow, } from '../types/dashboardReport.ts'; export const REPORT_TOTAL_LABEL = 'Total'; const isPresentNumber = (value: number | null | undefined): value is number => typeof value === 'number' && Number.isFinite(value); function sumPresent(values: Array): number | null { let total = 0; let any = false; for (const value of values) { if (!isPresentNumber(value)) continue; total += value; any = true; } return any ? total : null; } const sackAccuracy = (manual: number | null, iot: number | null): number | null => { if (manual != null && iot != null && manual > 0 && iot > 0) { return Math.round((Math.min(manual, iot) / Math.max(manual, iot)) * 1000) / 10; } if (manual === 0 && iot === 0) return 100; return null; }; export interface CountingTotalsRow { label: string; countBefore: number | null; mortality: number | null; harvest: number | null; harvestWeight: number | null; countAfter: number | null; iotCount: number | null; accuracy: number | null; } export interface FeedInTotalsRow { label: string; manualIn: number | null; iotIn: number | null; accuracy: number | null; } export interface FeedUseTotalsRow { label: string; manualUse: number | null; iotUse: number | null; accuracy: number | null; } export interface FeedOutTotalsRow { label: string; manualOut: number | null; iotOut: number | null; accuracy: number | null; } export function countingTotals(rows: DashboardReportCountingRow[]): CountingTotalsRow | null { if (!rows.length) return null; return { label: REPORT_TOTAL_LABEL, countBefore: null, mortality: sumPresent(rows.map((row) => row.mortality)), harvest: sumPresent(rows.map((row) => row.harvest)), harvestWeight: sumPresent(rows.map((row) => row.harvestWeight)), countAfter: null, iotCount: null, accuracy: null, }; } export function feedInTotals(rows: DashboardReportFeedInRow[]): FeedInTotalsRow | null { if (!rows.length) return null; const manualIn = sumPresent(rows.map((row) => row.manualIn)); const iotIn = sumPresent(rows.map((row) => row.iotIn)); return { label: REPORT_TOTAL_LABEL, manualIn, iotIn, accuracy: sackAccuracy(manualIn, iotIn), }; } export function feedUseTotals(rows: DashboardReportFeedUseRow[]): FeedUseTotalsRow | null { if (!rows.length) return null; const manualUse = sumPresent(rows.map((row) => row.manualUse)); const iotUse = sumPresent(rows.map((row) => row.iotUse)); return { label: REPORT_TOTAL_LABEL, manualUse, iotUse, accuracy: sackAccuracy(manualUse, iotUse), }; } export function feedOutTotals(rows: DashboardReportFeedOutRow[]): FeedOutTotalsRow | null { if (!rows.length) return null; const manualOut = sumPresent(rows.map((row) => row.manualOut)); const iotOut = sumPresent(rows.map((row) => row.iotOut)); return { label: REPORT_TOTAL_LABEL, manualOut, iotOut, accuracy: sackAccuracy(manualOut, iotOut), }; }