import { MessageFlags, SlashCommandBuilder, type Client } from "discord.js"; import type { Payload } from "payload"; import type { BotCommand } from "./index"; import { isStaff } from "@/bot/lib/roles"; import { processMission, reconcile } from "@/bot/services/evaluationReminders"; import { isMissionEvaluable } from "@/lib/evaluations"; import type { Mission } from "@/payload-types"; const missionLabel = (mission: Mission): string => mission.codeName ? `${mission.name} (${mission.codeName})` : mission.name; const resolveTargetMissions = async ( payload: Payload, input: string, ): Promise<{ mission?: Mission; error?: string }> => { const trimmed = input.trim(); try { const mission = await payload.findByID({ collection: "missions", id: trimmed, overrideAccess: true, depth: 0, }); return { mission: mission as unknown as Mission }; } catch { // Not an ID — fall through to a name / code-name search. } const res = await payload.find({ collection: "missions", overrideAccess: true, depth: 0, limit: 6, where: { or: [{ name: { like: trimmed } }, { codeName: { like: trimmed } }], }, }); const docs = res.docs as unknown as Mission[]; if (docs.length === 0) { return { error: `No mission matches "${trimmed}" (searched by ID, name, and code name).` }; } if (docs.length > 1) { const list = docs.map((m) => `• ${missionLabel(m)} — #${m.id}`).join("\n"); return { error: `Multiple missions match "${trimmed}". Be more specific:\n${list}` }; } return { mission: docs[0] }; }; export const remindEvaluationsCommand: BotCommand = { builder: new SlashCommandBuilder() .setName("remind-evaluations") .setDescription("Send leadership evaluation reminder DMs (staff only)") .addStringOption((option) => option .setName("mission") .setDescription("Mission ID, name, or code name. Omit to sweep all pending missions."), ) as SlashCommandBuilder, execute: async (interaction, payload) => { if (!interaction.inGuild() || !interaction.guild) { await interaction.reply({ content: "This command only works in a server.", flags: MessageFlags.Ephemeral, }); return; } const member = await interaction.guild.members.fetch(interaction.user.id); if (!(await isStaff(member, payload))) { await interaction.reply({ content: "You don't have permission to trigger evaluation reminders.", flags: MessageFlags.Ephemeral, }); return; } await interaction.deferReply({ flags: MessageFlags.Ephemeral }); const client = interaction.client as Client; const missionInput = interaction.options.getString("mission")?.trim(); try { if (missionInput) { const { mission, error } = await resolveTargetMissions(payload, missionInput); if (error || !mission) { await interaction.editReply(error ?? `No mission matches "${missionInput}".`); return; } if ( !isMissionEvaluable( mission.ownershipAndStatus?.status ?? "", mission.classification?.startDateTime ?? null, ) ) { await interaction.editReply( `**${missionLabel(mission)}** isn't evaluable yet — missions must be completed or past their scheduled start before reminders go out.`, ); return; } const sent = await processMission(client, payload, mission); await interaction.editReply( `Done — ${sent} evaluation reminder DM(s) sent for **${missionLabel(mission)}**.`, ); return; } const { processed, sent } = await reconcile(client, payload); await interaction.editReply( `Sweep complete — ${processed} pending mission(s) processed, ${sent} reminder DM(s) sent.`, ); } catch (error) { await interaction.editReply( `Reminder trigger failed: ${error instanceof Error ? error.message : "Unknown error"}`, ); } }, };