import type { NutrientKey, Nutrition } from '@/types/nutrition'; import { BASE_DAILY_TARGETS } from '@/common/constants/nutrition'; const SCORE_NUTRIENTS: { key: NutrientKey; weight: number }[] = [ { key: 'protein_g', weight: 12 }, { key: 'fiber_g', weight: 10 }, { key: 'omega_3_mg', weight: 10 }, { key: 'vitamin_d_mcg', weight: 8 }, { key: 'b12_mcg', weight: 7 }, { key: 'iron_mg', weight: 7 }, { key: 'calcium_mg', weight: 7 }, { key: 'magnesium_mg', weight: 7 }, { key: 'choline_mg', weight: 6 }, { key: 'dha_mg', weight: 6 }, { key: 'epa_mg', weight: 6 }, { key: 'potassium_mg', weight: 5 }, { key: 'zinc_mg', weight: 5 }, { key: 'c_mg', weight: 5 }, { key: 'a_mcg', weight: 5 }, { key: 'b9_mcg', weight: 5 }, { key: 'selenium_mcg', weight: 5 }, { key: 'iodine_mcg', weight: 5 }, { key: 'b6_mg', weight: 4 }, { key: 'e_mg', weight: 4 }, { key: 'k_mcg', weight: 4 }, { key: 'copper_mg', weight: 4 }, { key: 'manganese_mg', weight: 4 }, { key: 'b1_mg', weight: 3 }, { key: 'b2_mg', weight: 3 }, { key: 'b3_mg', weight: 3 }, { key: 'b5_mg', weight: 3 }, { key: 'biotin_mcg', weight: 3 }, { key: 'phosphorus_mg', weight: 3 }, { key: 'chromium_mcg', weight: 3 }, { key: 'molybdenum_mcg', weight: 3 }, { key: 'ala_mg', weight: 3 }, { key: 'soluble_fiber_g', weight: 3 }, { key: 'insoluble_fiber_g', weight: 3 }, { key: 'retinol_mcg', weight: 2 }, { key: 'dpa_mg', weight: 2 }, { key: 'omega_6_mg', weight: 2 }, { key: 'monounsaturated_fat_g', weight: 2 }, { key: 'polyunsaturated_fat_g', weight: 2 }, { key: 'tryptophan_mg', weight: 2 }, { key: 'tyrosine_mg', weight: 2 }, { key: 'valine_g', weight: 2 }, { key: 'glutamine_g', weight: 2 }, { key: 'lycopene_mcg', weight: 2 }, { key: 'lutein_zeaxanthin_mcg', weight: 2 }, { key: 'beta_carotene_mcg', weight: 2 }, { key: 'alpha_carotene_mcg', weight: 1 }, { key: 'cryptoxanthin_mcg', weight: 1 }, { key: 'anthocyanins_mg', weight: 2 }, { key: 'phytosterols_mg', weight: 1 }, { key: 'betaine_mg', weight: 1 }, { key: 'probiotics_cfu', weight: 2 }, { key: 'collagen_g', weight: 1 }, { key: 'coq10_mg', weight: 1 }, { key: 'curcumin_mg', weight: 1 }, { key: 'creatine_g', weight: 1 }, { key: 'resveratrol_mg', weight: 1 }, { key: 'astaxanthin_mcg', weight: 1 }, { key: 'water_ml', weight: 2 }, { key: 'caffeine_mg', weight: 1 }, { key: 'theobromine_mg', weight: 1 }, { key: 'taurine_mg', weight: 1 }, ]; const SCORE_FOOD_GROUPS: { key: NutrientKey; weight: number }[] = [ { key: 'usa_gov_dga_vegetables_cup_eq', weight: 8 }, { key: 'usa_gov_dga_fruits_cup_eq', weight: 5 }, { key: 'usa_gov_dga_protein_g', weight: 5 }, { key: 'usa_gov_dga_whole_grains_oz_eq', weight: 4 }, { key: 'usa_gov_dga_dairy_cup_eq', weight: 3 }, { key: 'usa_gov_dga_healthy_fats_tsp_eq', weight: 3 }, { key: 'usa_gov_dga_dark_green_veg_cup_eq', weight: 4 }, { key: 'usa_gov_dga_red_orange_veg_cup_eq', weight: 3 }, { key: 'usa_gov_dga_beans_peas_lentils_veg_cup_eq', weight: 3 }, { key: 'usa_gov_dga_starchy_veg_cup_eq', weight: 2 }, { key: 'usa_gov_dga_other_veg_cup_eq', weight: 2 }, ]; function fillRatio(consumed: number, target: number): number { if (target <= 0) return 0; const ratio = consumed / target; return Math.min(ratio, 1.5) / 1.5; } export function calculateNutritionScore( consumed: Nutrition, targets: Nutrition, uniqueIngredientCount: number ): number { const nutrientTotal = SCORE_NUTRIENTS.reduce((sum, n) => sum + n.weight, 0); const foodGroupTotal = SCORE_FOOD_GROUPS.reduce((sum, n) => sum + n.weight, 0); let nutrientScore = 0; for (const { key, weight } of SCORE_NUTRIENTS) { const c = consumed[key] ?? 0; const t = targets[key] ?? BASE_DAILY_TARGETS[key] ?? 1; nutrientScore += fillRatio(c, t) * weight; } const nutrientPct = nutrientScore / nutrientTotal; let foodGroupScore = 0; for (const { key, weight } of SCORE_FOOD_GROUPS) { const c = consumed[key] ?? 0; const t = targets[key] ?? BASE_DAILY_TARGETS[key] ?? 1; foodGroupScore += fillRatio(c, t) * weight; } const foodGroupPct = foodGroupScore / foodGroupTotal; const diversityBonus = Math.min(uniqueIngredientCount / 15, 1); const rawScore = nutrientPct * 45 + foodGroupPct * 45 + diversityBonus * 10; return Math.min(Math.max(rawScore, 0), 100); }