const { Pool } = require('pg'); const cache = { global: [], byGuild: new Map(), // guildId -> rows[] ready: false }; function inWindow(row, now = new Date()) { if (row.starts_at && now < new Date(row.starts_at)) return false; if (row.ends_at && now > new Date(row.ends_at)) return false; return true; } function pickWeighted(list) { if (!list.length) return null; const total = list.reduce((a, r) => a + (r.weight || 1), 0); let rnd = Math.random() * total; for (const r of list) { rnd -= (r.weight || 1); if (rnd <= 0) return r; } return list[0]; } async function loadAll(pool) { const { rows } = await pool.query( `SELECT id, name, activity_type, enabled, weight, scope, guild_id, starts_at, ends_at FROM bot_statuses WHERE enabled = TRUE` ); const now = new Date(); cache.global = rows.filter(r => r.scope === 'global' && inWindow(r, now)); cache.byGuild.clear(); for (const r of rows) { if (r.scope === 'guild' && inWindow(r, now) && r.guild_id) { const arr = cache.byGuild.get(r.guild_id) || []; arr.push(r); cache.byGuild.set(r.guild_id, arr); } } cache.ready = true; } async function initStatusCache(pool) { await loadAll(pool); // Live refresh when table changes (if you created the trigger) const client = await pool.connect(); await client.query('LISTEN status_change'); client.on('notification', async () => { try { await loadAll(pool); console.log('[status] cache refreshed via NOTIFY'); } catch (e) { console.error('[status] refresh error:', e); } }); // Safety: periodic refresh in case NOTIFY is missed setInterval(() => loadAll(pool).catch(() => {}), 5 * 60 * 1000); } function getNextStatus(guildId) { const rows = (guildId && cache.byGuild.get(guildId))?.length ? cache.byGuild.get(guildId) : cache.global; return pickWeighted(rows || []); } module.exports = { initStatusCache, getNextStatus };