import cron from "node-cron"; import { Client, TextChannel } from "discord.js"; import { cfg } from "./config"; import { TGSlot } from "../types"; import { polls, updatePollMessage } from "@systems/poll"; type PollCallback = (slot: TGSlot) => Promise; type CloseCallback = (slot: TGSlot) => Promise; type LockCallback = (slot: TGSlot) => Promise; let _scheduledTasks: cron.ScheduledTask[] = []; export function scheduleSlots( client: Client, onPollOpen: PollCallback, onPollLock: LockCallback, onPollClose: CloseCallback, ): void { _scheduledTasks.forEach((t) => t.stop()); _scheduledTasks = []; const tz = process.env.TZ ?? "Etc/GMT-2"; const slots = cfg("slots").filter((s) => s.active); for (const slot of slots) { // Poll open const [openHour, openMin] = slot.pollOpens.split(":").map(Number); _scheduledTasks.push(cron.schedule( `${openMin} ${openHour} * * *`, () => onPollOpen(slot), { timezone: tz } )); // Poll lock — exactly at tgHour (TG start, voting closes, lockedYesKeys snapshotted) _scheduledTasks.push(cron.schedule( `0 ${slot.tgHour} * * *`, () => onPollLock(slot), { timezone: tz } )); // Poll close — tgHour + closesAfter minutes (TG end, Submit Score button appears) const closeMinTotal = slot.tgHour * 60 + slot.closesAfter; const closeHour = Math.floor(closeMinTotal / 60) % 24; const closeMin = closeMinTotal % 60; _scheduledTasks.push(cron.schedule( `${closeMin} ${closeHour} * * *`, () => onPollClose(slot), { timezone: tz } )); _scheduledTasks.push(cron.schedule("0 0 * * *", async () => { const state = polls.get(slot.tgHour); if (!state?.locked) return; // only if poll has been locked (TG happened) const channel = await (client as any).channels.fetch(cfg("pollChannelId")) as TextChannel; await updatePollMessage(channel, slot.tgHour, undefined, false); console.log(`[${new Date().toISOString()}] Submit Score button removed.`); }, { timezone: tz })); } // Weekly reset — Monday 00:00 _scheduledTasks.push(cron.schedule("0 0 * * 1", () => { const { resetWeek } = require("./wrank"); resetWeek(); console.log("W.Rank weekly reset complete."); }, { timezone: tz })); console.log(`Scheduled ${slots.length} slot(s).`); }