const express = require('express'); const pool = require('../db/pool'); const router = express.Router(); // Validation helper const validateExercise = (data) => { const errors = []; if (!data.name || typeof data.name !== 'string' || !data.name.trim()) { errors.push('name is required and must be non-empty'); } if (data.difficulty && !['beginner', 'intermediate', 'advanced'].includes(data.difficulty)) { errors.push('difficulty must be beginner, intermediate, or advanced'); } if (data.muscle_groups && !Array.isArray(data.muscle_groups)) { errors.push('muscle_groups must be an array'); } if (data.equipment_needed && !Array.isArray(data.equipment_needed)) { errors.push('equipment_needed must be an array'); } return errors; }; // CREATE - Add new exercise router.post('/', async (req, res) => { try { const { name, description, instructions, muscle_groups, difficulty, equipment_needed, video_url, created_by } = req.body; const errors = validateExercise({ name, difficulty, muscle_groups, equipment_needed }); if (errors.length > 0) { return res.status(400).json({ error: 'Validation failed', details: errors }); } const query = ` INSERT INTO exercises (name, description, instructions, muscle_groups, difficulty, equipment_needed, video_url, created_by) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING * `; const result = await pool.query(query, [ name.trim(), description || null, instructions || null, muscle_groups || [], difficulty || 'intermediate', equipment_needed || [], video_url || null, created_by || 'system' ]); res.status(201).json(result.rows[0]); } catch (err) { if (err.code === '23505') { return res.status(409).json({ error: 'Exercise name already exists' }); } console.error('Error creating exercise:', err); res.status(500).json({ error: 'Failed to create exercise' }); } }); // READ - Get all exercises with search/filter router.get('/', async (req, res) => { try { const { search, difficulty, muscle_group, limit = 50, offset = 0 } = req.query; let query = 'SELECT * FROM exercises WHERE 1=1'; const params = []; let paramCount = 1; if (search) { query += ` AND (name ILIKE $${paramCount} OR description ILIKE $${paramCount})`; params.push(`%${search}%`); paramCount++; } if (difficulty) { query += ` AND difficulty = $${paramCount}`; params.push(difficulty); paramCount++; } if (muscle_group) { query += ` AND $${paramCount} = ANY(muscle_groups)`; params.push(muscle_group); paramCount++; } query += ` ORDER BY name ASC LIMIT $${paramCount} OFFSET $${paramCount + 1}`; params.push(parseInt(limit), parseInt(offset)); const result = await pool.query(query, params); res.json(result.rows); } catch (err) { console.error('Error fetching exercises:', err); res.status(500).json({ error: 'Failed to fetch exercises' }); } }); // READ - Get single exercise router.get('/:id', async (req, res) => { try { const result = await pool.query('SELECT * FROM exercises WHERE id = $1', [req.params.id]); if (result.rows.length === 0) { return res.status(404).json({ error: 'Exercise not found' }); } res.json(result.rows[0]); } catch (err) { console.error('Error fetching exercise:', err); res.status(500).json({ error: 'Failed to fetch exercise' }); } }); // UPDATE - Modify exercise router.put('/:id', async (req, res) => { try { const { name, description, instructions, muscle_groups, difficulty, equipment_needed, video_url } = req.body; const errors = validateExercise({ name, difficulty, muscle_groups, equipment_needed }); if (errors.length > 0) { return res.status(400).json({ error: 'Validation failed', details: errors }); } const query = ` UPDATE exercises SET name = $1, description = $2, instructions = $3, muscle_groups = $4, difficulty = $5, equipment_needed = $6, video_url = $7, updated_at = CURRENT_TIMESTAMP WHERE id = $8 RETURNING * `; const result = await pool.query(query, [ name.trim(), description || null, instructions || null, muscle_groups || [], difficulty || 'intermediate', equipment_needed || [], video_url || null, req.params.id ]); if (result.rows.length === 0) { return res.status(404).json({ error: 'Exercise not found' }); } res.json(result.rows[0]); } catch (err) { if (err.code === '23505') { return res.status(409).json({ error: 'Exercise name already exists' }); } console.error('Error updating exercise:', err); res.status(500).json({ error: 'Failed to update exercise' }); } }); // DELETE - Remove exercise router.delete('/:id', async (req, res) => { try { const result = await pool.query('DELETE FROM exercises WHERE id = $1 RETURNING *', [req.params.id]); if (result.rows.length === 0) { return res.status(404).json({ error: 'Exercise not found' }); } res.json({ message: 'Exercise deleted', id: req.params.id }); } catch (err) { console.error('Error deleting exercise:', err); res.status(500).json({ error: 'Failed to delete exercise' }); } }); module.exports = router;