import type { NutritionValues, Unit } from "@app/shared-types"; import { computeItemNutrition, roundNutrition, scaleNutrition, sumNutrition } from "./calc.js"; import type { IngredientUnitInfo } from "./units.js"; import type { NutritionDeclaration } from "@app/shared-types"; export interface RecipeIngredientForCalc { canonicalIngredientId: string; quantity: number; unit: Unit; optional?: boolean; } export interface IngredientNutritionSource extends IngredientUnitInfo { nutritionPer100: NutritionDeclaration; } export interface RecipeNutritionResult { perPortion: NutritionValues; total: NutritionValues; /** Ingredienser som inte kunde beräknas (saknad densitet etc.) – redovisas öppet. */ uncomputableIngredientIds: string[]; } /** * Beräkna ett recepts näringsvärden ur dess ingredienser – deterministiskt. * Valfria ingredienser exkluderas ur grundberäkningen. */ export function computeRecipeNutrition( ingredients: RecipeIngredientForCalc[], portions: number, sources: Map, ): RecipeNutritionResult { const parts: NutritionValues[] = []; const uncomputable: string[] = []; for (const ing of ingredients) { if (ing.optional) continue; const source = sources.get(ing.canonicalIngredientId); if (!source) { uncomputable.push(ing.canonicalIngredientId); continue; } const values = computeItemNutrition(ing.quantity, ing.unit, source.nutritionPer100, source); if (values == null) { uncomputable.push(ing.canonicalIngredientId); continue; } parts.push(values); } const total = sumNutrition(parts); const perPortion = portions > 0 ? roundNutrition(scaleNutrition(total, 1 / portions)) : roundNutrition(total); return { perPortion, total: roundNutrition(total), uncomputableIngredientIds: uncomputable }; }