import { createCommand } from "@/lib/utils"; import { SlashCommandBuilder, EmbedBuilder, MessageFlags } from "discord.js"; import { inventoryService } from "@/modules/inventory/inventory.service"; import { userService } from "@/modules/user/user.service"; import { createErrorEmbed, createSuccessEmbed } from "@lib/embeds"; import { inventory, items } from "@/db/schema"; import { eq, and, like } from "drizzle-orm"; import { DrizzleClient } from "@/lib/DrizzleClient"; import type { ItemUsageData } from "@/lib/types"; export const use = createCommand({ data: new SlashCommandBuilder() .setName("use") .setDescription("Use an item from your inventory") .addNumberOption(option => option.setName("item") .setDescription("The item to use") .setRequired(true) .setAutocomplete(true) ), execute: async (interaction) => { if (!interaction.isChatInputCommand()) { if (interaction.isAutocomplete()) { const focusedValue = interaction.options.getFocused(); const userId = interaction.user.id; // Fetch owned items that are usable const userInventory = await DrizzleClient.query.inventory.findMany({ where: eq(inventory.userId, BigInt(userId)), with: { item: true }, limit: 10 }); const filtered = userInventory.filter(entry => { const matchName = entry.item.name.toLowerCase().includes(focusedValue.toLowerCase()); const usageData = entry.item.usageData as ItemUsageData | null; const isUsable = usageData && usageData.effects && usageData.effects.length > 0; return matchName && isUsable; }); await interaction.respond( filtered.map(entry => ({ name: `${entry.item.name} (${entry.quantity})`, value: entry.item.id })) ); } return; } await interaction.deferReply(); const itemId = interaction.options.getNumber("item", true); const user = await userService.getOrCreateUser(interaction.user.id, interaction.user.username); try { const result = await inventoryService.useItem(user.id, itemId); // Check for side effects like Role assignment that need Discord API access // The service returns the usageData, so we can re-check simple effects or just check the results log? // Actually, we put "TEMP_ROLE" inside results log, AND we can check usageData here for strict role assignment if we want to separate concerns. // But for now, let's rely on the service to have handled database state, and we handle Discord state here if needed? // WAIT - I put the role assignment placeholder in the service but it returned a result string. // The service cannot assign the role directly because it doesn't have the member object easily (requires fetching). // So we should iterate results or usageData here. const usageData = result.usageData; if (usageData) { for (const effect of usageData.effects) { if (effect.type === 'TEMP_ROLE') { try { const member = await interaction.guild?.members.fetch(user.id); if (member) { await member.roles.add(effect.roleId); } } catch (e) { console.error("Failed to assign role in /use command:", e); result.results.push("⚠️ Failed to assign role (Check bot permissions)"); } } } } const embed = createSuccessEmbed( result.results.map(r => `• ${r}`).join("\n"), `Used ${result.usageData.effects.length > 0 ? 'Item' : 'Item'}` // Generic title, improves below ); embed.setTitle("Item Used!"); await interaction.editReply({ embeds: [embed] }); } catch (error: any) { await interaction.editReply({ embeds: [createErrorEmbed(error.message)] }); } } });