"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.UtilsService = void 0; const common_1 = require("@nestjs/common"); const sequelize_1 = require("@nestjs/sequelize"); const sequelize_2 = require("sequelize"); const user_model_1 = require("../models/user.model"); const food_item_model_1 = require("../models/food-item.model"); const meal_model_1 = require("../models/meal.model"); const meal_food_model_1 = require("../models/meal-food.model"); const water_log_model_1 = require("../models/water-log.model"); const weight_log_model_1 = require("../models/weight-log.model"); const meal_plan_model_1 = require("../models/meal-plan.model"); const planned_food_model_1 = require("../models/planned-food.model"); const daily_summary_model_1 = require("../models/daily-summary.model"); let UtilsService = class UtilsService { constructor(userModel, foodItemModel, mealModel, waterLogModel, weightLogModel, mealPlanModel, plannedFoodModel, dailySummaryModel) { this.userModel = userModel; this.foodItemModel = foodItemModel; this.mealModel = mealModel; this.waterLogModel = waterLogModel; this.weightLogModel = weightLogModel; this.mealPlanModel = mealPlanModel; this.plannedFoodModel = plannedFoodModel; this.dailySummaryModel = dailySummaryModel; } calculateBMR(weightKg, heightCm, age, gender) { let bmr; if (gender.toLowerCase() === 'male') { bmr = 10 * weightKg + 6.25 * heightCm - 5 * age + 5; } else { bmr = 10 * weightKg + 6.25 * heightCm - 5 * age - 161; } return Math.round(bmr); } calculateTDEE(bmr, activityLevel) { const multipliers = { sedentary: 1.2, light: 1.375, moderate: 1.55, active: 1.725, very_active: 1.9, }; const multiplier = multipliers[activityLevel] || 1.55; return Math.round(bmr * multiplier); } calculateMacroTargets(weightKg, goalType = 'recomp') { let protein, carbs, fat; if (goalType === 'muscle_gain') { protein = weightKg * 2.4; carbs = weightKg * 3.5; fat = weightKg * 1.0; } else if (goalType === 'weight_loss') { protein = weightKg * 2.2; carbs = weightKg * 2.0; fat = weightKg * 0.8; } else { protein = weightKg * 2.2; carbs = weightKg * 2.5; fat = weightKg * 0.9; } return { protein_g: Math.round(protein), carbs_g: Math.round(carbs), fat_g: Math.round(fat), }; } async calculateDailyTotals(userId, targetDate = new Date()) { const dateStr = targetDate instanceof Date ? targetDate.toISOString().split('T')[0] : targetDate; const meals = await this.mealModel.findAll({ where: { UserId: userId, date: dateStr, }, include: [ { model: meal_food_model_1.MealFood, include: [food_item_model_1.FoodItem], }, ], }); const totals = { calories: 0, protein: 0, carbs: 0, fat: 0, meals: [], }; for (const meal of meals) { const mealTotals = { calories: 0, protein: 0, carbs: 0, fat: 0, }; const mealFoods = []; for (const mf of meal.mealFoods) { const quantity = mf.quantity || 1.0; const food = mf.foodItem; const calories = mf.calories_consumed || food.calories * quantity; const protein = mf.protein_consumed || food.protein_g * quantity; const carbs = mf.carbs_consumed || food.carbs_g * quantity; const fat = mf.fat_consumed || food.fat_g * quantity; mealTotals.calories += calories; mealTotals.protein += protein; mealTotals.carbs += carbs; mealTotals.fat += fat; mealFoods.push({ name: food.name, quantity: quantity, calories: calories, }); } totals.calories += mealTotals.calories; totals.protein += mealTotals.protein; totals.carbs += mealTotals.carbs; totals.fat += mealTotals.fat; totals.meals.push({ id: meal.id, type: meal.meal_type, time: meal.time ? meal.time.substring(0, 5) : null, totals: mealTotals, foods: mealFoods, }); } return totals; } async calculateWaterTotal(userId, targetDate = new Date()) { const dateStr = targetDate instanceof Date ? targetDate.toISOString().split('T')[0] : targetDate; const waterLogs = await this.waterLogModel.findAll({ where: { UserId: userId, date: dateStr, }, }); const total = waterLogs.reduce((sum, log) => sum + log.amount_ml, 0); return { total_ml: total, logs: waterLogs.map((log) => ({ id: log.id, amount_ml: log.amount_ml, time: log.time ? log.time.substring(0, 5) : null, })), }; } async getWeightTrend(userId, days = 7) { const endDate = new Date(); const startDate = new Date(); startDate.setDate(endDate.getDate() - (days - 1)); const startDateStr = startDate.toISOString().split('T')[0]; const endDateStr = endDate.toISOString().split('T')[0]; const weightLogs = await this.weightLogModel.findAll({ where: { UserId: userId, date: { [sequelize_2.Op.between]: [startDateStr, endDateStr], }, }, order: [['date', 'ASC']], }); return weightLogs.map((log) => ({ date: log.date, weight_kg: log.weight_kg, })); } async getCalorieTrend(userId, days = 7) { const endDate = new Date(); const startDate = new Date(); startDate.setDate(endDate.getDate() - (days - 1)); const trend = []; const currentDate = new Date(startDate); while (currentDate <= endDate) { const dateStr = currentDate.toISOString().split('T')[0]; const totals = await this.calculateDailyTotals(userId, dateStr); trend.push({ date: dateStr, calories: Math.round(totals.calories), protein: Math.round(totals.protein), carbs: Math.round(totals.carbs), fat: Math.round(totals.fat), }); currentDate.setDate(currentDate.getDate() + 1); } return trend; } async updateDailySummary(userId, targetDate = new Date()) { const dateStr = targetDate instanceof Date ? targetDate.toISOString().split('T')[0] : targetDate; const nutrition = await this.calculateDailyTotals(userId, dateStr); const water = await this.calculateWaterTotal(userId, dateStr); const weightLog = await this.weightLogModel.findOne({ where: { UserId: userId, date: dateStr, }, }); const weight = weightLog ? weightLog.weight_kg : null; const user = await this.userModel.findByPk(userId); const targetCalories = user ? user.target_daily_calories : 2000; let summary = await this.dailySummaryModel.findOne({ where: { UserId: userId, date: dateStr, }, }); if (!summary) { summary = await this.dailySummaryModel.create({ UserId: userId, date: dateStr, }); } summary.total_calories = nutrition.calories; summary.total_protein_g = nutrition.protein; summary.total_carbs_g = nutrition.carbs; summary.total_fat_g = nutrition.fat; summary.total_water_ml = water.total_ml; summary.calories_remaining = targetCalories - nutrition.calories; summary.weight_kg = weight; try { await summary.save(); return summary; } catch (e) { console.error(`Error updating daily summary: ${e}`); return null; } } getMacroPercentages(proteinG, carbsG, fatG) { const proteinCal = proteinG * 4; const carbsCal = carbsG * 4; const fatCal = fatG * 9; const totalCal = proteinCal + carbsCal + fatCal; if (totalCal === 0) { return { protein: 0, carbs: 0, fat: 0 }; } return { protein: Math.round((proteinCal / totalCal) * 100), carbs: Math.round((carbsCal / totalCal) * 100), fat: Math.round((fatCal / totalCal) * 100), }; } suggestFoodsForMacros(remainingProtein, remainingCarbs, remainingFat) { const suggestions = []; if (remainingProtein > 30) { suggestions.push({ category: 'High Protein Ulam', examples: ['Grilled Tilapia', 'Chicken Tinola', 'Grilled Chicken'], }); } if (remainingCarbs > 40) { suggestions.push({ category: 'Carbs', examples: ['White Rice', 'Pandesal', 'Sweet Potato'], }); } if (remainingFat > 20) { suggestions.push({ category: 'Healthy Fats', examples: ['Sisig', 'Lechon Kawali', 'Bicol Express'], }); } if (remainingProtein > 20 && remainingCarbs > 30) { suggestions.push({ category: 'Balanced Meals', examples: ['Tapsilog', 'Chicken Adobo with Rice', 'Sinigang'], }); } return suggestions; } async generateDailyMealPlan(userId, dateStr) { try { const user = await this.userModel.findByPk(userId); const targetCalories = user ? user.target_daily_calories : 2000; const targets = { breakfast: Math.round(targetCalories * 0.25), lunch: Math.round(targetCalories * 0.35), dinner: Math.round(targetCalories * 0.3), snack: Math.round(targetCalories * 0.1), }; const foods = await this.foodItemModel.findAll(); const foodByCat = { almusal: foods.filter((f) => f.category === 'almusal'), ulam: foods.filter((f) => ['ulam', 'sabaw'].includes(f.category)), kanin: foods.filter((f) => f.category === 'kanin'), gulay: foods.filter((f) => f.category === 'gulay'), meryenda: foods.filter((f) => f.category === 'meryenda'), }; const allFoods = foods; const pickRandom = (arr) => (arr.length > 0 ? arr[Math.floor(Math.random() * arr.length)] : null); const generateMeal = async (mealType, targetCal) => { let currentCal = 0; const selectedFoods = []; if (mealType === 'breakfast') { const main = pickRandom(foodByCat.almusal) || pickRandom(allFoods); if (main) { selectedFoods.push({ food: main, qty: 1 }); currentCal += main.calories; } } else if (['lunch', 'dinner'].includes(mealType)) { const rice = pickRandom(foodByCat.kanin); const ulam = pickRandom(foodByCat.ulam) || pickRandom(allFoods); const gulay = pickRandom(foodByCat.gulay); if (rice) { selectedFoods.push({ food: rice, qty: 1 }); currentCal += rice.calories; } if (ulam) { selectedFoods.push({ food: ulam, qty: 1 }); currentCal += ulam.calories; } if (gulay && currentCal < targetCal) { selectedFoods.push({ food: gulay, qty: 1 }); currentCal += gulay.calories; } } else if (mealType === 'snack') { const snack = pickRandom(foodByCat.meryenda) || pickRandom(allFoods); if (snack) { selectedFoods.push({ food: snack, qty: 1 }); currentCal += snack.calories; } } if (currentCal > 0 && selectedFoods.length > 0) { const mealPlan = await this.mealPlanModel.create({ UserId: userId, date: dateStr, meal_type: mealType, is_completed: false, }); for (const item of selectedFoods) { await this.plannedFoodModel.create({ MealPlanId: mealPlan.id, FoodItemId: item.food.id, quantity: item.qty, }); } } }; await this.mealPlanModel.destroy({ where: { UserId: userId, date: dateStr, }, }); await generateMeal('breakfast', targets.breakfast); await generateMeal('lunch', targets.lunch); await generateMeal('dinner', targets.dinner); await generateMeal('snack', targets.snack); return true; } catch (error) { console.error('Error generating meal plan:', error); throw error; } } }; exports.UtilsService = UtilsService; exports.UtilsService = UtilsService = __decorate([ (0, common_1.Injectable)(), __param(0, (0, sequelize_1.InjectModel)(user_model_1.User)), __param(1, (0, sequelize_1.InjectModel)(food_item_model_1.FoodItem)), __param(2, (0, sequelize_1.InjectModel)(meal_model_1.Meal)), __param(3, (0, sequelize_1.InjectModel)(water_log_model_1.WaterLog)), __param(4, (0, sequelize_1.InjectModel)(weight_log_model_1.WeightLog)), __param(5, (0, sequelize_1.InjectModel)(meal_plan_model_1.MealPlan)), __param(6, (0, sequelize_1.InjectModel)(planned_food_model_1.PlannedFood)), __param(7, (0, sequelize_1.InjectModel)(daily_summary_model_1.DailySummary)), __metadata("design:paramtypes", [Object, Object, Object, Object, Object, Object, Object, Object]) ], UtilsService); //# sourceMappingURL=utils.service.js.map