const DEFAULT_COOLDOWNS = { work: 3600, daily: 72000, slots: 60, coinflip: 30, rep: 43200, trivia: 30, heist: 1800, duel: 300, gift: 60, trade: 60 }; const userCooldowns = new Map(); const cooldownCache = new Map(); const CACHE_TTL = 5 * 60 * 1000; async function getCommandCooldown(supabase, guildId, commandName) { if (!supabase) { return DEFAULT_COOLDOWNS[commandName] || 0; } const cacheKey = `${guildId}-${commandName}`; const cached = cooldownCache.get(cacheKey); if (cached && Date.now() - cached.timestamp < CACHE_TTL) { return cached.value; } try { const { data } = await supabase .from('command_cooldowns') .select('cooldown_seconds') .eq('guild_id', guildId) .eq('command_name', commandName) .maybeSingle(); const cooldown = data?.cooldown_seconds ?? DEFAULT_COOLDOWNS[commandName] ?? 0; cooldownCache.set(cacheKey, { value: cooldown, timestamp: Date.now() }); return cooldown; } catch (error) { console.error('Failed to fetch cooldown:', error.message); return DEFAULT_COOLDOWNS[commandName] || 0; } } function getCooldownKey(guildId, userId, commandName) { return `${guildId}-${userId}-${commandName}`; } function getUserCooldown(guildId, userId, commandName) { const key = getCooldownKey(guildId, userId, commandName); return userCooldowns.get(key); } function setUserCooldown(guildId, userId, commandName) { const key = getCooldownKey(guildId, userId, commandName); userCooldowns.set(key, Date.now()); } function clearUserCooldown(guildId, userId, commandName) { const key = getCooldownKey(guildId, userId, commandName); userCooldowns.delete(key); } async function checkCooldown(supabase, guildId, userId, commandName) { const cooldownSeconds = await getCommandCooldown(supabase, guildId, commandName); if (cooldownSeconds === 0) { return { onCooldown: false, cooldownSeconds: 0 }; } const cooldownMs = cooldownSeconds * 1000; const lastUsed = getUserCooldown(guildId, userId, commandName); if (!lastUsed) { return { onCooldown: false, cooldownSeconds }; } const elapsed = Date.now() - lastUsed; const remaining = cooldownMs - elapsed; if (remaining <= 0) { return { onCooldown: false, cooldownSeconds }; } return { onCooldown: true, remaining: remaining, remainingSeconds: Math.ceil(remaining / 1000), cooldownSeconds }; } function formatCooldownRemaining(remainingMs) { const seconds = Math.ceil(remainingMs / 1000); if (seconds < 60) { return `${seconds}s`; } const minutes = Math.floor(seconds / 60); const secs = seconds % 60; if (minutes < 60) { return secs > 0 ? `${minutes}m ${secs}s` : `${minutes}m`; } const hours = Math.floor(minutes / 60); const mins = minutes % 60; if (hours < 24) { return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`; } const days = Math.floor(hours / 24); const hrs = hours % 24; return hrs > 0 ? `${days}d ${hrs}h` : `${days}d`; } function invalidateCooldownCache(guildId, commandName = null) { if (commandName) { cooldownCache.delete(`${guildId}-${commandName}`); } else { for (const key of cooldownCache.keys()) { if (key.startsWith(`${guildId}-`)) { cooldownCache.delete(key); } } } } module.exports = { getCommandCooldown, getUserCooldown, setUserCooldown, clearUserCooldown, checkCooldown, formatCooldownRemaining, invalidateCooldownCache, DEFAULT_COOLDOWNS };