const express = require('express'); const router = express.Router(); const jwt = require('jsonwebtoken'); const Recipe = require('../models/Recipe'); // 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(); }); } // Get ingredient suggestions for autocomplete router.get('/ingredients/suggestions', async (req, res) => { try { const { q } = req.query; // Search query if (!q || q.length < 2) { return res.json([]); } // Aggregate unique ingredient names from all recipes const suggestions = await Recipe.aggregate([ { $unwind: '$ingredients' }, { $match: { 'ingredients.name': { $regex: q, $options: 'i' } } }, { $group: { _id: { $toLower: '$ingredients.name' }, name: { $first: '$ingredients.name' }, count: { $sum: 1 } } }, { $sort: { count: -1, name: 1 } }, { $limit: 10 }, { $project: { _id: 0, name: 1, count: 1 } } ]); res.json(suggestions); } catch (error) { res.status(500).json({ error: error.message }); } }); // Get unit suggestions for a specific ingredient router.get('/ingredients/units', async (req, res) => { try { const { ingredient } = req.query; if (!ingredient) { return res.json([]); } // Find units used with this specific ingredient const unitSuggestions = await Recipe.aggregate([ { $unwind: '$ingredients' }, { $match: { 'ingredients.name': { $regex: ingredient, $options: 'i' } } }, { $group: { _id: { $toLower: '$ingredients.unit' }, unit: { $first: '$ingredients.unit' }, count: { $sum: 1 }, avgAmount: { $avg: '$ingredients.amount' } } }, { $sort: { count: -1, unit: 1 } }, { $limit: 8 }, { $project: { _id: 0, unit: 1, count: 1, avgAmount: { $round: ['$avgAmount', 2] } } } ]); res.json(unitSuggestions); } catch (error) { res.status(500).json({ error: error.message }); } }); // Get all recipes router.get('/', async (req, res) => { try { const { category, difficulty, search } = req.query; let filter = {}; if (category) filter.category = category; if (difficulty) filter.difficulty = difficulty; if (search) { filter.$or = [ { title: { $regex: search, $options: 'i' } }, { description: { $regex: search, $options: 'i' } } ]; } const recipes = await Recipe.find(filter).sort({ createdAt: -1 }); res.json(recipes); } catch (error) { res.status(500).json({ error: error.message }); } }); // Get recipe by ID router.get('/:id', async (req, res) => { try { const recipe = await Recipe.findById(req.params.id); if (!recipe) { return res.status(404).json({ error: 'Recipe not found' }); } res.json(recipe); } catch (error) { res.status(500).json({ error: error.message }); } }); // Create new recipe (protected route) router.post('/', authenticateToken, async (req, res) => { try { const recipe = new Recipe({ ...req.body, createdBy: req.userId // Add user ID to track who created the recipe }); await recipe.save(); res.status(201).json(recipe); } catch (error) { res.status(400).json({ error: error.message }); } }); // Update recipe router.put('/:id', async (req, res) => { try { const recipe = await Recipe.findByIdAndUpdate( req.params.id, req.body, { new: true, runValidators: true } ); if (!recipe) { return res.status(404).json({ error: 'Recipe not found' }); } res.json(recipe); } catch (error) { res.status(400).json({ error: error.message }); } }); // Delete recipe router.delete('/:id', async (req, res) => { try { const recipe = await Recipe.findByIdAndDelete(req.params.id); if (!recipe) { return res.status(404).json({ error: 'Recipe not found' }); } res.json({ message: 'Recipe deleted successfully' }); } catch (error) { res.status(500).json({ error: error.message }); } }); module.exports = router;