import { describe, test, expect, spyOn, beforeEach, mock } from "bun:test";
import { handleItemWizardInteraction, renderWizard } from "./item_wizard";
import { ButtonInteraction, ModalSubmitInteraction, StringSelectMenuInteraction } from "discord.js";

// Mock Setup
const valuesMock = mock((_args: any) => Promise.resolve());
const insertMock = mock(() => ({ values: valuesMock }));

mock.module("@shared/db/DrizzleClient", () => ({
    DrizzleClient: {
        insert: insertMock
    }
}));

mock.module("@db/schema", () => ({
    items: "items_schema"
}));

describe("ItemWizard", () => {
    const userId = "test-user-123";

    beforeEach(() => {
        valuesMock.mockClear();
        insertMock.mockClear();
        // Since draftSession is internal, we can't easily clear it. 
        // We will use unique user IDs or rely on overwrite behavior.
    });

    // Helper to create base interaction
    const createBaseInteraction = (id: string, customId: string) => ({
        user: { id },
        customId,
        deferUpdate: mock(() => Promise.resolve()),
        editReply: mock(() => Promise.resolve()),
        update: mock(() => Promise.resolve()),
        showModal: mock(() => Promise.resolve()),
        followUp: mock(() => Promise.resolve()),
        reply: mock(() => Promise.resolve()),
    });

    test("renderWizard should return initial state for new user", () => {
        const result = renderWizard(`new-${Date.now()}`);
        expect(result.embeds).toHaveLength(1);
        expect(result.embeds[0]?.data.title).toContain("New Item");
        expect(result.components).toHaveLength(2);
    });

    test("handleItemWizardInteraction should handle details modal submit", async () => {
        const uid = `user-details-${Date.now()}`;
        renderWizard(uid); // Init session

        const interaction = {
            ...createBaseInteraction(uid, "createitem_modal_details"),
            isButton: () => false,
            isStringSelectMenu: () => false,
            isModalSubmit: () => true,
            isMessageComponent: () => false,
            fields: {
                getTextInputValue: (key: string) => {
                    if (key === "name") return "Updated Name";
                    if (key === "desc") return "Updated Desc";
                    if (key === "rarity") return "Legendary";
                    return "";
                }
            },
        } as unknown as ModalSubmitInteraction;

        await handleItemWizardInteraction(interaction);

        expect(interaction.deferUpdate).toHaveBeenCalled();
        const result = renderWizard(uid);
        expect(result.embeds[0]?.data.title).toContain("Updated Name");
    });

    test("handleItemWizardInteraction should handle economy modal submit", async () => {
        const uid = `user-economy-${Date.now()}`;
        renderWizard(uid);

        const interaction = {
            ...createBaseInteraction(uid, "createitem_modal_economy"),
            isButton: () => false,
            isStringSelectMenu: () => false,
            isModalSubmit: () => true,
            isMessageComponent: () => false,
            fields: {
                getTextInputValue: (key: string) => (key === "price" ? "500" : "")
            },
        } as unknown as ModalSubmitInteraction;

        await handleItemWizardInteraction(interaction);

        const result = renderWizard(uid);
        const economyField = result.embeds[0]?.data.fields?.find(f => f.name === "Economy");
        expect(economyField?.value).toContain("500 🪙");
    });

    test("handleItemWizardInteraction should handle visuals modal submit", async () => {
        const uid = `user-visuals-${Date.now()}`;
        renderWizard(uid);

        const interaction = {
            ...createBaseInteraction(uid, "createitem_modal_visuals"),
            isButton: () => false,
            isStringSelectMenu: () => false,
            isModalSubmit: () => true,
            isMessageComponent: () => false,
            fields: {
                getTextInputValue: (key: string) => {
                    if (key === "icon") return "http://icon.com";
                    if (key === "image") return "http://image.com";
                    return "";
                }
            },
        } as unknown as ModalSubmitInteraction;

        await handleItemWizardInteraction(interaction);

        const result = renderWizard(uid);
        expect(result.embeds[0]?.data.thumbnail?.url).toBe("http://icon.com");
        expect(result.embeds[0]?.data.image?.url).toBe("http://image.com");
    });

    test("handleItemWizardInteraction should flow through adding an effect", async () => {
        const uid = `user-effect-${Date.now()}`;
        renderWizard(uid);

        // 1. Start Add Effect
        const startInteraction = {
            ...createBaseInteraction(uid, "createitem_addeffect_start"),
            isButton: () => true,
            isStringSelectMenu: () => false,
            isModalSubmit: () => false,
            isMessageComponent: () => true,
        } as unknown as ButtonInteraction;
        await handleItemWizardInteraction(startInteraction);
        expect(startInteraction.update).toHaveBeenCalled(); // Should show select menu

        // 2. Select Effect Type
        const selectInteraction = {
            ...createBaseInteraction(uid, "createitem_select_effect_type"),
            isButton: () => false,
            isStringSelectMenu: () => true,
            isModalSubmit: () => false,
            isMessageComponent: () => true,
            values: ["ADD_XP"]
        } as unknown as StringSelectMenuInteraction;
        await handleItemWizardInteraction(selectInteraction);
        expect(selectInteraction.showModal).toHaveBeenCalled(); // Should show config modal

        // 3. Submit Effect Config Modal
        const modalInteraction = {
            ...createBaseInteraction(uid, "createitem_modal_effect"),
            isButton: () => false,
            isStringSelectMenu: () => false,
            isModalSubmit: () => true,
            isMessageComponent: () => false,
            fields: {
                getTextInputValue: (key: string) => (key === "amount" ? "1000" : "")
            },
        } as unknown as ModalSubmitInteraction;
        await handleItemWizardInteraction(modalInteraction);

        // Verify Effect Added
        const result = renderWizard(uid);
        const effectsField = result.embeds[0]?.data.fields?.find(f => f.name === "Usage Effects");
        expect(effectsField?.value).toContain("ADD_XP");
        expect(effectsField?.value).toContain("1000");
    });

    test("handleItemWizardInteraction should save item to database", async () => {
        const uid = `user-save-${Date.now()}`;
        renderWizard(uid);

        // Set name first so we can check it
        const nameInteraction = {
            ...createBaseInteraction(uid, "createitem_modal_details"),
            isButton: () => false,
            isStringSelectMenu: () => false,
            isModalSubmit: () => true,
            isMessageComponent: () => false,
            fields: {
                getTextInputValue: (key: string) => {
                    if (key === "name") return "Saved Item";
                    if (key === "desc") return "Desc";
                    if (key === "rarity") return "Common";
                    return "";
                }
            },
        } as unknown as ModalSubmitInteraction;
        await handleItemWizardInteraction(nameInteraction);

        // Save
        const saveInteraction = {
            ...createBaseInteraction(uid, "createitem_save"),
            isButton: () => true,
            isStringSelectMenu: () => false,
            isModalSubmit: () => false,
            isMessageComponent: () => true,
        } as unknown as ButtonInteraction;

        await handleItemWizardInteraction(saveInteraction);

        expect(valuesMock).toHaveBeenCalled();
        const calls = valuesMock.mock.calls as any[];
        if (calls.length > 0) {
            const callArgs = calls[0][0];
            expect(callArgs).toMatchObject({
                name: "Saved Item",
                description: "Desc",
                rarity: "Common",
                // Add other fields as needed
            });
        }

        expect(saveInteraction.editReply).toHaveBeenCalledWith(expect.objectContaining({
            content: expect.stringContaining("successfully")
        }));
    });

    test("handleItemWizardInteraction should cancel and clear session", async () => {
        const uid = `user-cancel-${Date.now()}`;
        renderWizard(uid);

        const interaction = {
            ...createBaseInteraction(uid, "createitem_cancel"),
            isButton: () => true, // Technically any component
            isStringSelectMenu: () => false,
            isModalSubmit: () => false,
            isMessageComponent: () => true,
        } as unknown as ButtonInteraction;

        await handleItemWizardInteraction(interaction);

        expect(interaction.update).toHaveBeenCalledWith(expect.objectContaining({
            content: expect.stringContaining("cancelled")
        }));

        // Verify session is gone by checking if renderWizard returns default New Item
        // Let's modify it first
        const modInteraction = {
            ...createBaseInteraction(uid, "createitem_modal_details"),
            isButton: () => false,
            isStringSelectMenu: () => false,
            isModalSubmit: () => true,
            isMessageComponent: () => false,
            fields: {
                getTextInputValue: (key: string) => (key === "name" ? "Modified" : "x")
            },
        } as unknown as ModalSubmitInteraction;
        await handleItemWizardInteraction(modInteraction);

        // Now Cancel
        await handleItemWizardInteraction(interaction);

        // New render should be "New Item" not "Modified"
        const result = renderWizard(uid);
        expect(result.embeds[0]?.data.title).toContain("New Item");
        expect(result.embeds[0]?.data.title).not.toContain("Modified");
    });
});
