const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js"); const { getCookieBalance, changeCookies, claimCooldown, temporaryEphemeralReply } = require("./cookieEconomy"); const { trackProfileEvent } = require("./profileSystem"); /* * ============================================================ * CONFIG * ============================================================ */ const COLLECT_COOLDOWN = 60 * 60; const COLLECT_MIN = 1; const COLLECT_MAX = 1000; const COLLECT_COOLDOWN_KEY = "collect"; /* * ============================================================ * SHARED COLLECT LOGIC * ============================================================ * * This is the one authoritative implementation used by: * * - /cookies collect * - Crumb Saucer Cookie Bakery * * It does not reply/update Discord itself. */ async function collectCookies( interaction, userId = interaction.user.id ) { const cooldown = await claimCooldown( userId, interaction.guildId, COLLECT_COOLDOWN_KEY, COLLECT_COOLDOWN ); if (!cooldown.claimed) { const balance = await getCookieBalance( userId ); return { collected: false, cooldown, balance, amount: 0 }; } const amount = Math.floor( Math.random() * ( COLLECT_MAX - COLLECT_MIN + 1 ) ) + COLLECT_MIN; await changeCookies( userId, amount ); await trackProfileEvent( interaction, userId, { type: "cookie_gain", source: "collect", amount } ); const balance = await getCookieBalance( userId ); return { collected: true, cooldown, balance, amount }; } /* * ============================================================ * SHARED EMBED BUILDERS * ============================================================ */ function buildCollectSuccessEmbed( userId, result, footerType = "crumbSaucerCollect" ) { return new EmbedBuilder() .setTitle( "🍪 Fresh Batch!" ) .setDescription( [ `You collected **${result.amount.toLocaleString()} Cookies**! 🍪`, "", `Your next batch will be ready .` ].join("\n") ) .addFields({ name: "Your Vault", value: `**${result.balance.toLocaleString()} 🍪**` }) .setFooter({ text: `${footerType}:${userId}` }); } function buildCollectCooldownEmbed( userId, result, footerType = "crumbSaucerCollect" ) { return new EmbedBuilder() .setTitle( "🍪 Cookie Bakery" ) .setDescription( [ "Your next batch isn't ready yet.", "", `Come back .` ].join("\n") ) .addFields({ name: "Your Vault", value: `**${result.balance.toLocaleString()} 🍪**` }) .setFooter({ text: `${footerType}:${userId}` }); } /* * ============================================================ * SHOW SAUCER COLLECT PAGE * ============================================================ */ async function showCollectPage( interaction ) { const ownerId = getCollectOwner( interaction ); if ( ownerId !== interaction.user.id ) { return temporaryEphemeralReply( interaction, { content: "This isn't your Crumb Saucer session." } ); } const balance = await getCookieBalance( interaction.user.id ); const embed = new EmbedBuilder() .setTitle( "🍪 Crumb Saucer Cookie Bakery" ) .setDescription( [ "Fresh Cookies are prepared regularly.", "", "Press **Collect Cookies** to claim your batch.", "", "Your collection cooldown is shared with `/cookies collect`." ].join("\n") ) .addFields({ name: "Your Vault", value: `**${balance.toLocaleString()} 🍪**` }) .setFooter({ text: `crumbSaucerCollect:${interaction.user.id}` }); return interaction.update({ embeds: [embed], components: buildCollectButtons() }); } /* * ============================================================ * SAUCER COLLECT WRAPPER * ============================================================ */ async function collectCookiesFromSaucer( interaction ) { const ownerId = getCollectOwner( interaction ); if ( ownerId !== interaction.user.id ) { return temporaryEphemeralReply( interaction, { content: "This isn't your Crumb Saucer session." } ); } const result = await collectCookies( interaction, interaction.user.id ); const embed = result.collected ? buildCollectSuccessEmbed( interaction.user.id, result ) : buildCollectCooldownEmbed( interaction.user.id, result ); return interaction.update({ embeds: [embed], components: buildCollectButtons() }); } /* * ============================================================ * BUTTONS * ============================================================ */ function buildCollectButtons() { return [ new ActionRowBuilder() .addComponents( new ButtonBuilder() .setCustomId( "crumbSaucerCollect" ) .setLabel( "Collect Cookies" ) .setEmoji( "🍪" ) .setStyle( ButtonStyle.Success ), new ButtonBuilder() .setCustomId( "crumbSaucerBack" ) .setLabel( "Crumb Saucer" ) .setEmoji( "◀️" ) .setStyle( ButtonStyle.Secondary ) ) ]; } /* * ============================================================ * OWNER * ============================================================ */ function getCollectOwner( interaction ) { const footer = interaction.message ?.embeds?.[0] ?.footer ?.text; const parts = footer?.split(":") ?? []; if ( parts[0] === "crumbSaucer" ) { return parts[1]; } if ( parts[0] === "crumbSaucerCollect" ) { return parts[1]; } return null; } /* * ============================================================ * EXPORTS * ============================================================ */ module.exports = { collectCookies, buildCollectSuccessEmbed, buildCollectCooldownEmbed, showCollectPage, collectCookiesFromSaucer, COLLECT_COOLDOWN, COLLECT_MIN, COLLECT_MAX };