import type { IngredientNutritionItem } from "@/types/ingredient-catalog.types"; export interface MacroTotals { calories: number; protein: number; fat: number; carbs: number; } export interface MacroIngredientInput { catalogItemId?: number | null; amountGrams?: number | null; unit?: string | null; name?: string; } export function hasNonMacroUnit(unit?: string | null): boolean { if (!unit?.trim()) return false; const u = unit.trim().toLowerCase(); return u === "do smaku" || u === "optional" || u === "opcjonalnie" || u === "szczypta"; } export function shouldIncludeIngredientInMacroSum(ing: MacroIngredientInput): boolean { return Boolean( ing.catalogItemId && ing.amountGrams != null && ing.amountGrams > 0 && !hasNonMacroUnit(ing.unit), ); } export function isUnlinkedMacroIngredient(ing: MacroIngredientInput): boolean { if (!ing.name?.trim()) return false; if (hasNonMacroUnit(ing.unit)) return false; return Boolean(ing.amountGrams != null && ing.amountGrams > 0 && !ing.catalogItemId); } export function countUnlinkedMacroIngredients(ingredients: MacroIngredientInput[]): number { return ingredients.filter(isUnlinkedMacroIngredient).length; } export function estimateMacrosFromCatalog( ingredients: MacroIngredientInput[], catalogItems: Pick< IngredientNutritionItem, "id" | "caloriesPer100G" | "proteinGPer100G" | "fatGPer100G" | "carbsGPer100G" >[], ): MacroTotals | null { let calories = 0; let protein = 0; let fat = 0; let carbs = 0; let hasAny = false; for (const ing of ingredients) { if (!shouldIncludeIngredientInMacroSum(ing)) continue; const cat = catalogItems.find((c) => c.id === ing.catalogItemId); if (!cat) continue; const scale = Number(ing.amountGrams) / 100; calories += Math.round(cat.caloriesPer100G * scale); protein += cat.proteinGPer100G * scale; fat += cat.fatGPer100G * scale; carbs += cat.carbsGPer100G * scale; hasAny = true; } return hasAny ? { calories, protein, fat, carbs } : null; }