import type { ActivityLevel, DailyTargets, GoalType, Sex } from "@app/shared-types"; /** * Energiberäkning enligt Mifflin–St Jeor. Detta är vägledning baserad på * officiella rekommendationer – Appen är inte medicinsk rådgivning (spec §6, §21). */ export interface EnergyProfile { sex: Sex; age: number; heightCm: number; weightKg: number; activityLevel: ActivityLevel; primaryGoal?: GoalType | undefined; } const ACTIVITY_FACTORS: Record = { sedentary: 1.2, light: 1.375, moderate: 1.55, active: 1.725, very_active: 1.9, }; /** Justering per mål (kcal/dag). Konservativa, väldokumenterade nivåer. */ const GOAL_ADJUSTMENTS: Partial> = { lose_weight: -500, gain_weight: 400, build_muscle: 250, maintain_weight: 0, }; /** Lägsta rekommenderade energiintag – under detta kapas aldrig målet (säkerhetsgolv). */ const MIN_KCAL = 1200; export function bmrMifflinStJeor( p: Pick, ): number { const base = 10 * p.weightKg + 6.25 * p.heightCm - 5 * p.age; if (p.sex === "male") return base + 5; if (p.sex === "female") return base - 161; // Ospecificerat: medelvärde av formlerna, transparent redovisat i UI. return base - 78; } export function tdee(p: EnergyProfile): number { return bmrMifflinStJeor(p) * ACTIVITY_FACTORS[p.activityLevel]; } export interface DailyTargetsResult { targets: DailyTargets; basis: { bmrKcal: number; tdeeKcal: number; goalAdjustmentKcal: number; activityLevel: ActivityLevel; }; } /** * Dagsmål: energi via TDEE + måljustering; protein per kg kroppsvikt; * fett som andel av energi; kolhydrater = resten; fiber 3 g/MJ (nordisk rekommendation); * salt max 6 g/dag. */ export function computeDailyTargets(p: EnergyProfile): DailyTargetsResult { const bmr = bmrMifflinStJeor(p); const maintenance = tdee(p); const adjustment = GOAL_ADJUSTMENTS[p.primaryGoal ?? "maintain_weight"] ?? 0; const kcal = Math.max(MIN_KCAL, Math.round(maintenance + adjustment)); const proteinPerKg = p.primaryGoal === "build_muscle" || p.primaryGoal === "more_protein" ? 1.8 : p.primaryGoal === "lose_weight" ? 1.6 : 1.2; const proteinG = Math.round(p.weightKg * proteinPerKg); const fatShare = p.primaryGoal === "less_fat" ? 0.25 : 0.3; const fatG = Math.round((kcal * fatShare) / 9); const carbsKcal = Math.max(0, kcal - proteinG * 4 - fatG * 9); const carbsG = Math.round(carbsKcal / 4); // 3 g fiber per MJ (1 MJ ≈ 239 kcal) const fiberG = Math.round((kcal / 239) * 3); return { targets: { kcal, proteinG, carbsG, fatG, fiberG, saltMaxG: 6 }, basis: { bmrKcal: Math.round(bmr), tdeeKcal: Math.round(maintenance), goalAdjustmentKcal: adjustment, activityLevel: p.activityLevel, }, }; } /** Standardmål när profil saknas (visas tydligt som schablon i appen). */ export const DEFAULT_TARGETS: DailyTargets = { kcal: 2000, proteinG: 80, carbsG: 220, fatG: 67, fiberG: 25, saltMaxG: 6, };