const admin = require("firebase-admin"); const { onSchedule } = require("firebase-functions/v2/scheduler"); const { refList } = require("../index"); const firestore = refList.projects.firestore; function buildMonthContext(referenceDate) { const current = referenceDate ? new Date(referenceDate) : new Date(); current.setHours(0, 0, 0, 0); current.setDate(1); const target = new Date(current); target.setMonth(target.getMonth() - 1); const month = target.getMonth(); const year = target.getFullYear(); const monthKey = `${year}-${String(month + 1).padStart(2, "0")}`; const rangeStart = new Date(year, month, 1, 0, 0, 0, 0); const rangeEnd = new Date(year, month + 1, 0, 23, 59, 59, 999); return { year, month: month + 1, monthKey, rangeStart, rangeEnd, }; } exports.snapshotMonthlyTopSongs = onSchedule( { schedule: "5 0 1 * *", timeZone: "Europe/Paris", }, async (event) => { const { scheduleTime } = event; const context = buildMonthContext( scheduleTime ? new Date(scheduleTime) : new Date() ); const topProjectsSnap = await refList.projects .orderBy("views", "desc") .limit(3) .get(); const topProjects = topProjectsSnap.docs.map((doc, index) => { const data = doc.data() || {}; return { rank: index + 1, projectId: doc.id, title: data.title || null, userId: data.userId || null, userName: data.userName || null, coverUrl: data.coverUrl || null, songUrl: data.songUrl || null, views: data.views || 0, }; }); const docRef = firestore .collection("monthlyTopSongs") .doc(context.monthKey); const existingSnapshot = await docRef.get(); const payload = { monthKey: context.monthKey, month: context.month, year: context.year, range: { start: admin.firestore.Timestamp.fromDate(context.rangeStart), end: admin.firestore.Timestamp.fromDate(context.rangeEnd), }, topProjects, totalProjects: topProjects.length, updatedAt: admin.firestore.FieldValue.serverTimestamp(), }; if (!existingSnapshot.exists) { payload.createdAt = admin.firestore.FieldValue.serverTimestamp(); } await docRef.set(payload, { merge: true }); } );