const express = require('express'); const { collections, FieldValue, docToObject } = require('../db/firestore'); const authMiddleware = require('../middleware/auth'); const router = express.Router(); router.use(authMiddleware); function enrollmentDocId(userId, programId) { return `${userId}_${programId}`; } async function annotateEnrollment(programDocs, userId) { if (programDocs.length === 0) return []; const enrollSnaps = await Promise.all( programDocs.map((d) => collections.userPrograms.doc(enrollmentDocId(userId, d.id)).get() ) ); return programDocs.map((doc, i) => { const program = docToObject(doc); const e = enrollSnaps[i]; program.is_enrolled = e.exists; if (e.exists) { const ed = e.data(); program.current_week = ed.current_week ?? 1; program.is_active = ed.is_active ?? true; program.enrolled_at = ed.enrolled_at?.toDate?.().toISOString() ?? null; } else { program.current_week = null; program.is_active = null; } return program; }); } // GET /api/programs/me/active — must come before /:id router.get('/me/active', async (req, res) => { try { const enrollSnap = await collections.userPrograms .where('userId', '==', req.userId) .where('is_active', '==', true) .get(); const programs = await Promise.all( enrollSnap.docs.map(async (e) => { const ed = e.data(); const p = await collections.programs.doc(ed.programId).get(); if (!p.exists) return null; const program = docToObject(p); program.current_week = ed.current_week ?? 1; program.enrolled_at = ed.enrolled_at?.toDate?.().toISOString() ?? null; return program; }) ); res.json({ programs: programs.filter(Boolean) }); } catch (err) { console.error(err); res.status(500).json({ message: 'Server error' }); } }); // GET /api/programs router.get('/', async (req, res) => { const { difficulty, category } = req.query; try { let query = collections.programs; if (difficulty) query = query.where('difficulty', '==', difficulty); // Firestore can't do case-insensitive substring; for category we filter exact match. if (category) query = query.where('category', '==', category); const snap = await query.get(); const sorted = snap.docs.slice().sort((a, b) => { const ad = a.data(), bd = b.data(); if ((bd.is_featured ? 1 : 0) !== (ad.is_featured ? 1 : 0)) return (bd.is_featured ? 1 : 0) - (ad.is_featured ? 1 : 0); const at = ad.created_at?.toMillis?.() ?? 0; const bt = bd.created_at?.toMillis?.() ?? 0; return bt - at; }); const programs = await annotateEnrollment(sorted, req.userId); res.json({ programs }); } catch (err) { console.error(err); res.status(500).json({ message: 'Server error' }); } }); // GET /api/programs/:id router.get('/:id', async (req, res) => { try { const snap = await collections.programs.doc(req.params.id).get(); if (!snap.exists) return res.status(404).json({ message: 'Program not found' }); const [program] = await annotateEnrollment([snap], req.userId); res.json({ program }); } catch (err) { console.error(err); res.status(500).json({ message: 'Server error' }); } }); // POST /api/programs/:id/enroll router.post('/:id/enroll', async (req, res) => { try { const enrollRef = collections.userPrograms.doc(enrollmentDocId(req.userId, req.params.id)); const programRef = collections.programs.doc(req.params.id); const enrollSnap = await enrollRef.get(); const wasEnrolled = enrollSnap.exists; await enrollRef.set( { userId: req.userId, programId: req.params.id, enrolled_at: enrollSnap.exists ? enrollSnap.data().enrolled_at : FieldValue.serverTimestamp(), current_week: 1, is_active: true, completed_at: null, }, { merge: true } ); if (!wasEnrolled) { await programRef.update({ total_enrolled: FieldValue.increment(1) }); } res.json({ message: 'Enrolled successfully' }); } catch (err) { console.error(err); res.status(500).json({ message: 'Server error' }); } }); // DELETE /api/programs/:id/enroll router.delete('/:id/enroll', async (req, res) => { try { const enrollRef = collections.userPrograms.doc(enrollmentDocId(req.userId, req.params.id)); await enrollRef.set({ is_active: false }, { merge: true }); res.json({ message: 'Unenrolled' }); } catch (err) { console.error(err); res.status(500).json({ message: 'Server error' }); } }); module.exports = router;