'use strict'; const { EmbedBuilder, MessageFlags } = require('discord.js'); const { mongoose } = require('../../db-connection'); const { CONFIG } = require('../../config'); const { parsePeriod, shapeStats } = require('../../services/statsShaping'); const PERIOD_PRESETS = ['7 days', '30 days', '3 months', '6 months', '1 year']; const TIER_LABELS = { 1: 'Tier 2', 2: 'Tier 3' }; function tierLabel(n) { return TIER_LABELS[n] || `Tier ${n + 1}`; } function formatTierMap(obj) { const keys = Object.keys(obj).map(Number).sort((a, b) => a - b); if (!keys.length) return '0'; return keys.map(k => `${tierLabel(k)}: ${obj[k]}`).join(', '); } async function handleStatsAutocomplete(interaction) { const focused = (interaction.options.getFocused() || '').trim(); const lower = focused.toLowerCase(); const suggestions = PERIOD_PRESETS .filter(p => !focused || p.toLowerCase().includes(lower)) .map(p => ({ name: p, value: p })); // Echo typed input as an extra suggestion when it differs from all presets. if (focused && !PERIOD_PRESETS.some(p => p.toLowerCase() === lower)) { suggestions.unshift({ name: focused, value: focused }); } await interaction.respond(suggestions.slice(0, 25)); } async function handleStats(interaction, _deps) { const StaffAction = (_deps && _deps.StaffAction) || mongoose.model('StaffAction'); const nowMs = (_deps && typeof _deps.now === 'function') ? _deps.now() : Date.now(); const adminIds = (_deps && _deps.adminIds != null) ? _deps.adminIds : CONFIG.STATS_ADMIN_IDS; const memberUser = interaction.options.getUser('member'); const periodStr = interaction.options.getString('period'); const source = interaction.options.getString('source') || 'all'; if (memberUser && !adminIds.includes(interaction.user.id)) { return interaction.reply({ content: 'You can only view your own stats.', flags: MessageFlags.Ephemeral }); } const target = memberUser ? memberUser.id : interaction.user.id; const period = parsePeriod(periodStr); const cutoff = new Date(nowMs - period.durationMs); let events; try { events = await StaffAction.find({ createdAt: { $gte: cutoff }, $or: [ { staffId: target }, { resolverId: target }, { toId: target }, { fromId: target } ] }).lean(); } catch (err) { console.error('handleStats query error:', err); return interaction.reply({ content: 'Failed to load stats. Please try again.', flags: MessageFlags.Ephemeral }).catch(() => {}); } const stats = shapeStats(events, target, source); const targetName = memberUser ? memberUser.username : interaction.user.username; const sourceLabel = source === 'all' ? 'all sources' : source; const cweKeys = Object.keys(stats.claimsWhileEscalated).map(Number).sort((a, b) => a - b); const cweText = cweKeys.length ? `\n↳ while escalated: ${cweKeys.map(k => `${tierLabel(k)}: ${stats.claimsWhileEscalated[k]}`).join(', ')}` : ''; const embed = new EmbedBuilder() .setTitle(`Stats — ${targetName} — ${period.label}`) .setDescription(`Source: ${sourceLabel}`) .setColor(CONFIG.EMBED_COLOR_INFO) .addFields([ { name: 'Claims', value: `${stats.claims}${cweText}`, inline: true }, { name: 'Closes', value: `${stats.closes} (unclaimed: ${stats.unclaimedAtClose})`, inline: true }, { name: 'Resolved (credit)', value: `${stats.resolved}`, inline: true }, { name: 'Escalations', value: formatTierMap(stats.escalations), inline: true }, { name: 'De-escalations', value: formatTierMap(stats.deescalations), inline: true }, { name: 'Transfers', value: `In: ${stats.transfersIn} | Out: ${stats.transfersOut}`, inline: true }, { name: 'Reopens', value: `${stats.reopens}`, inline: true }, { name: 'Email / Discord split', value: [ `Email — claims: ${stats.bySource.email.claims}, closes: ${stats.bySource.email.closes}, resolved: ${stats.bySource.email.resolved}`, `Discord — claims: ${stats.bySource.discord.claims}, closes: ${stats.bySource.discord.closes}, resolved: ${stats.bySource.discord.resolved}` ].join('\n'), inline: false } ]); await interaction.reply({ embeds: [embed], flags: MessageFlags.Ephemeral }); } module.exports = { handleStats, handleStatsAutocomplete };