const express = require('express'); const router = express.Router(); const UserSelection = require('../models/UserSelection'); const Recipe = require('../models/Recipe'); const jwt = require('jsonwebtoken'); // Middleware to authenticate JWT token function authenticateToken(req, res, next) { const authHeader = req.headers['authorization']; const token = authHeader && authHeader.split(' ')[1]; if (!token) { return res.status(401).json({ error: 'Access token required' }); } jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => { if (err) { return res.status(403).json({ error: 'Invalid or expired token' }); } req.userId = decoded.userId; next(); }); } // Helper function to aggregate ingredients async function aggregateIngredients(selectedRecipes) { const aggregated = {}; for (const selection of selectedRecipes) { const recipe = await Recipe.findById(selection.recipeId); if (!recipe) continue; for (const ingredient of recipe.ingredients) { const key = `${ingredient.name}_${ingredient.unit}`; if (!aggregated[key]) { aggregated[key] = { name: ingredient.name, totalAmount: 0, unit: ingredient.unit, recipes: [] }; } const totalAmount = ingredient.amount * selection.quantity; aggregated[key].totalAmount += totalAmount; aggregated[key].recipes.push({ recipeId: recipe._id, recipeTitle: recipe.title, amount: ingredient.amount, quantity: selection.quantity }); } } return Object.values(aggregated); } // Get user's selections router.get('/', authenticateToken, async (req, res) => { try { let userSelection = await UserSelection.findOne({ userId: req.userId }) .populate('selectedRecipes.recipeId', 'title description imageUrl category'); if (!userSelection) { userSelection = new UserSelection({ userId: req.userId, selectedRecipes: [], aggregatedIngredients: [] }); await userSelection.save(); } res.json(userSelection); } catch (error) { res.status(500).json({ error: error.message }); } }); // Add recipe to user's selection router.post('/add', authenticateToken, async (req, res) => { try { const { recipeId, quantity = 1 } = req.body; // Verify recipe exists const recipe = await Recipe.findById(recipeId); if (!recipe) { return res.status(404).json({ error: 'Recipe not found' }); } let userSelection = await UserSelection.findOne({ userId: req.userId }); if (!userSelection) { userSelection = new UserSelection({ userId: req.userId, selectedRecipes: [], aggregatedIngredients: [] }); } // Check if recipe is already selected const existingIndex = userSelection.selectedRecipes.findIndex( item => item.recipeId.toString() === recipeId ); if (existingIndex >= 0) { // Update quantity if recipe already exists userSelection.selectedRecipes[existingIndex].quantity += quantity; } else { // Add new recipe selection userSelection.selectedRecipes.push({ recipeId, quantity, addedAt: new Date() }); } // Recalculate aggregated ingredients userSelection.aggregatedIngredients = await aggregateIngredients(userSelection.selectedRecipes); await userSelection.save(); // Populate recipe details for response await userSelection.populate('selectedRecipes.recipeId', 'title description imageUrl category'); res.json(userSelection); } catch (error) { res.status(500).json({ error: error.message }); } }); // Update recipe quantity in selection router.put('/update', authenticateToken, async (req, res) => { try { const { recipeId, quantity } = req.body; if (quantity < 0) { return res.status(400).json({ error: 'Quantity must be positive' }); } const userSelection = await UserSelection.findOne({ userId: req.userId }); if (!userSelection) { return res.status(404).json({ error: 'No selections found' }); } const recipeIndex = userSelection.selectedRecipes.findIndex( item => item.recipeId.toString() === recipeId ); if (recipeIndex === -1) { return res.status(404).json({ error: 'Recipe not found in selections' }); } if (quantity === 0) { // Remove recipe if quantity is 0 userSelection.selectedRecipes.splice(recipeIndex, 1); } else { // Update quantity userSelection.selectedRecipes[recipeIndex].quantity = quantity; } // Recalculate aggregated ingredients userSelection.aggregatedIngredients = await aggregateIngredients(userSelection.selectedRecipes); await userSelection.save(); await userSelection.populate('selectedRecipes.recipeId', 'title description imageUrl category'); res.json(userSelection); } catch (error) { res.status(500).json({ error: error.message }); } }); // Remove recipe from selection router.delete('/remove/:recipeId', authenticateToken, async (req, res) => { try { const { recipeId } = req.params; const userSelection = await UserSelection.findOne({ userId: req.userId }); if (!userSelection) { return res.status(404).json({ error: 'No selections found' }); } userSelection.selectedRecipes = userSelection.selectedRecipes.filter( item => item.recipeId.toString() !== recipeId ); // Recalculate aggregated ingredients userSelection.aggregatedIngredients = await aggregateIngredients(userSelection.selectedRecipes); await userSelection.save(); await userSelection.populate('selectedRecipes.recipeId', 'title description imageUrl category'); res.json(userSelection); } catch (error) { res.status(500).json({ error: error.message }); } }); // Clear all selections router.delete('/clear', authenticateToken, async (req, res) => { try { const userSelection = await UserSelection.findOne({ userId: req.userId }); if (!userSelection) { return res.status(404).json({ error: 'No selections found' }); } userSelection.selectedRecipes = []; userSelection.aggregatedIngredients = []; await userSelection.save(); res.json(userSelection); } catch (error) { res.status(500).json({ error: error.message }); } }); module.exports = router;