import { createCommand } from "@shared/lib/utils";
import { SlashCommandBuilder, MessageFlags, ComponentType } from "discord.js";
import { inventoryService } from "@shared/modules/inventory/inventory.service";
import { userService } from "@shared/modules/user/user.service";
import { createWarningEmbed, createErrorEmbed } from "@lib/embeds";
import {
    getInventoryListMessage,
    getEmptyInventoryMessage,
    getItemDetailMessage,
    getDiscardConfirmMessage,
    appendUseBackButton,
    sortInventoryItems,
    ITEMS_PER_PAGE,
    type InventoryEntry,
} from "@/modules/inventory/inventory.view";
import { getLootboxResultMessage } from "@/modules/inventory/inventory.view";
import {
    parseInventoryCustomId,
    executeItemUse,
} from "@/modules/inventory/inventory.interaction";
import { UserError } from "@shared/lib/errors";

export const inventory = createCommand({
    data: new SlashCommandBuilder()
        .setName("inventory")
        .setDescription("View your or another user's inventory")
        .addSubcommand(sub =>
            sub.setName("list")
                .setDescription("View your or another user's inventory")
                .addUserOption(option =>
                    option.setName("user")
                        .setDescription("User to view")
                        .setRequired(false)
                )
        )
        .addSubcommand(sub =>
            sub.setName("view")
                .setDescription("View details of a specific item")
                .addNumberOption(option =>
                    option.setName("item")
                        .setDescription("The item to view")
                        .setRequired(true)
                        .setAutocomplete(true)
                )
        ),
    execute: async (interaction) => {
        await interaction.deferReply();

        const viewerId = interaction.user.id;
        const subcommand = interaction.options.getSubcommand();

        if (subcommand === "view") {
            // Direct item detail view
            const itemId = interaction.options.getNumber("item", true);
            const user = await userService.getOrCreateUser(viewerId, interaction.user.username);
            if (!user) {
                await interaction.editReply({ embeds: [createWarningEmbed("Failed to load user data.", "Error")] });
                return;
            }

            const entries = await inventoryService.getInventory(user.id.toString());
            const entry = entries.find((e: any) => e.item.id === itemId);
            if (!entry) {
                await interaction.editReply({ embeds: [createWarningEmbed("Item not found in your inventory.", "Not Found")] });
                return;
            }

            const ownerId = user.id.toString();
            let currentPage = 0;
            let selectedItemId: number | null = itemId;

            const response = await interaction.editReply(
                getItemDetailMessage(entry as InventoryEntry, viewerId, ownerId) as any
            );

            await setupCollector(interaction, response, viewerId, ownerId, user.username, currentPage, selectedItemId);
            return;
        }

        // "list" subcommand
        const targetUser = interaction.options.getUser("user") || interaction.user;

        if (targetUser.bot) {
            await interaction.editReply({ embeds: [createWarningEmbed("Bots do not have inventories.", "Inventory Check")] });
            return;
        }

        const user = await userService.getOrCreateUser(targetUser.id, targetUser.username);
        if (!user) {
            await interaction.editReply({ embeds: [createWarningEmbed("Failed to load user data.", "Error")] });
            return;
        }

        const ownerId = user.id.toString();
        const entries = await inventoryService.getInventory(ownerId);

        if (!entries || entries.length === 0) {
            await interaction.editReply(getEmptyInventoryMessage(user.username) as any);
            return;
        }

        let currentPage = 0;
        let selectedItemId: number | null = null;

        const response = await interaction.editReply(
            getInventoryListMessage(entries as InventoryEntry[], user.username, currentPage, viewerId, ownerId) as any
        );

        await setupCollector(interaction, response, viewerId, ownerId, user.username, currentPage, selectedItemId);
    },
    autocomplete: async (interaction) => {
        const focusedValue = interaction.options.getFocused();
        const userId = interaction.user.id;
        const results = await inventoryService.getAutocompleteItems(userId, focusedValue);
        await interaction.respond(results);
    },
});

async function setupCollector(
    interaction: any,
    response: any,
    viewerId: string,
    ownerId: string,
    username: string,
    initialPage: number,
    initialItemId: number | null,
) {
    let currentPage = initialPage;
    let selectedItemId = initialItemId;

    const collector = response.createMessageComponentCollector({
        time: 120_000,
    });

    collector.on("collect", async (i: any) => {
        if (i.user.id !== viewerId) return;

        const parsed = parseInventoryCustomId(i.customId);
        if (!parsed) return;

        try {
            await i.deferUpdate();

            // Re-fetch inventory for fresh data
            const entries = await inventoryService.getInventory(ownerId);
            const sorted = sortInventoryItems(entries as InventoryEntry[]);

            switch (parsed.action) {
                case "select": {
                    const itemId = parseInt(i.values[0]);
                    const entry = sorted.find(e => e.item.id === itemId);
                    if (!entry) break;
                    selectedItemId = itemId;
                    await interaction.editReply(
                        getItemDetailMessage(entry, viewerId, ownerId)
                    );
                    break;
                }

                case "prev": {
                    currentPage = Math.max(0, currentPage - 1);
                    selectedItemId = null;
                    await interaction.editReply(
                        getInventoryListMessage(sorted, username, currentPage, viewerId, ownerId)
                    );
                    break;
                }

                case "next": {
                    currentPage = currentPage + 1;
                    selectedItemId = null;
                    await interaction.editReply(
                        getInventoryListMessage(sorted, username, currentPage, viewerId, ownerId)
                    );
                    break;
                }

                case "back": {
                    selectedItemId = null;
                    if (sorted.length === 0) {
                        await interaction.editReply(getEmptyInventoryMessage(username));
                    } else {
                        await interaction.editReply(
                            getInventoryListMessage(sorted, username, currentPage, viewerId, ownerId)
                        );
                    }
                    break;
                }

                case "use": {
                    if (viewerId !== ownerId || !selectedItemId) break;
                    try {
                        const result = await executeItemUse(i, viewerId, selectedItemId);
                        const message = getLootboxResultMessage(result.results, result.item);
                        await interaction.editReply(appendUseBackButton(message, viewerId) as any);
                    } catch (error) {
                        if (error instanceof UserError) {
                            await interaction.editReply({
                                embeds: [createErrorEmbed(error.message)],
                                components: [],
                                flags: undefined,
                            });
                        } else {
                            throw error;
                        }
                    }
                    break;
                }

                case "use_back": {
                    // Return from use result to detail or list
                    if (!selectedItemId) break;
                    const entry = sorted.find(e => e.item.id === selectedItemId);
                    if (entry) {
                        await interaction.editReply(
                            getItemDetailMessage(entry, viewerId, ownerId)
                        );
                    } else {
                        selectedItemId = null;
                        if (sorted.length === 0) {
                            await interaction.editReply(getEmptyInventoryMessage(username));
                        } else {
                            await interaction.editReply(
                                getInventoryListMessage(sorted, username, currentPage, viewerId, ownerId)
                            );
                        }
                    }
                    break;
                }

                case "discard": {
                    if (viewerId !== ownerId || !selectedItemId) break;
                    const entry = sorted.find(e => e.item.id === selectedItemId);
                    if (!entry) break;
                    await interaction.editReply(
                        getDiscardConfirmMessage(entry, viewerId)
                    );
                    break;
                }

                case "discard_confirm": {
                    if (viewerId !== ownerId || !selectedItemId) break;
                    try {
                        await inventoryService.removeItem(ownerId, selectedItemId, 1n);

                        const freshEntries = await inventoryService.getInventory(ownerId);
                        const freshSorted = sortInventoryItems(freshEntries as InventoryEntry[]);
                        const freshEntry = freshSorted.find(e => e.item.id === selectedItemId);

                        if (freshEntry) {
                            await interaction.editReply(
                                getItemDetailMessage(freshEntry, viewerId, ownerId)
                            );
                        } else {
                            selectedItemId = null;
                            if (freshSorted.length === 0) {
                                await interaction.editReply(getEmptyInventoryMessage(username));
                            } else {
                                await interaction.editReply(
                                    getInventoryListMessage(freshSorted, username, currentPage, viewerId, ownerId)
                                );
                            }
                        }
                    } catch (error) {
                        if (error instanceof UserError) {
                            await interaction.editReply({
                                embeds: [createErrorEmbed(error.message)],
                                components: [],
                                flags: undefined,
                            });
                        } else {
                            throw error;
                        }
                    }
                    break;
                }

                case "discard_cancel": {
                    if (!selectedItemId) break;
                    const entry = sorted.find(e => e.item.id === selectedItemId);
                    if (!entry) break;
                    await interaction.editReply(
                        getItemDetailMessage(entry, viewerId, ownerId)
                    );
                    break;
                }
            }
        } catch (error) {
            console.error("Inventory interaction error:", error);
        }
    });

    collector.on("end", async () => {
        try {
            // Re-render current view as static (no interactive components)
            const entries = await inventoryService.getInventory(ownerId);
            const sorted = sortInventoryItems(entries as InventoryEntry[]);

            if (selectedItemId) {
                const entry = sorted.find(e => e.item.id === selectedItemId);
                if (entry) {
                    // Show detail view without action buttons
                    const msg = getItemDetailMessage(entry, viewerId, ownerId);
                    // Replace components with empty to remove buttons but keep container content
                    await interaction.editReply(msg);
                    return;
                }
            }

            if (sorted.length === 0) {
                await interaction.editReply(getEmptyInventoryMessage(username));
            } else {
                await interaction.editReply(
                    getInventoryListMessage(sorted, username, currentPage, viewerId, ownerId)
                );
            }
        } catch {
            // If re-rendering fails, at least try to clear gracefully
            interaction.editReply({ components: [] }).catch(() => {});
        }
    });
}
