import { describe, expect, test, mock, beforeEach, spyOn } from "bun:test";
import { systemEvents, EVENTS } from "@shared/lib/events";

// Mock Discord.js Client and related classes
mock.module("discord.js", () => ({
    Client: class {
        constructor() { }
        on() { }
        once() { }
        login() { }
        destroy() { }
        removeAllListeners() { }
    },
    Collection: Map,
    GatewayIntentBits: { Guilds: 1, MessageContent: 1, GuildMessages: 1, GuildMembers: 1 },
    REST: class {
        setToken() { return this; }
        put() { return Promise.resolve([]); }
    },
    Routes: {
        applicationGuildCommands: () => 'guild_route',
        applicationCommands: () => 'global_route'
    }
}));

// Mock loaders to avoid filesystem access during client init
mock.module("../lib/loaders/CommandLoader", () => ({
    CommandLoader: class {
        constructor() { }
        loadFromDirectory() { return Promise.resolve({ loaded: 0, skipped: 0, errors: [] }); }
    }
}));
mock.module("../lib/loaders/EventLoader", () => ({
    EventLoader: class {
        constructor() { }
        loadFromDirectory() { return Promise.resolve({ loaded: 0, skipped: 0, errors: [] }); }
    }
}));

// Mock dashboard service to prevent network/db calls during event handling
mock.module("@shared/modules/economy/lootdrop.service", () => ({
    lootdropService: { clearCaches: mock(async () => { }) }
}));
mock.module("@shared/modules/trade/trade.service", () => ({
    tradeService: { clearSessions: mock(() => { }) }
}));
mock.module("@/modules/admin/item_wizard", () => ({
    clearDraftSessions: mock(() => { })
}));
mock.module("@shared/modules/dashboard/dashboard.service", () => ({
    dashboardService: {
        recordEvent: mock(() => Promise.resolve())
    }
}));

describe("AuroraClient System Events", () => {
    let AuroraClient: any;

    beforeEach(async () => {
        systemEvents.removeAllListeners();
        const module = await import("./BotClient");
        AuroraClient = module.AuroraClient;
        AuroraClient.maintenanceMode = false;
        // MUST call explicitly now
        await AuroraClient.setupSystemEvents();
    });

    /**
     * Test Case: Maintenance Mode Toggle
     * Requirement: Client state should update when event is received
     */
    test("should toggle maintenanceMode when MAINTENANCE_MODE event is received", async () => {
        systemEvents.emit(EVENTS.ACTIONS.MAINTENANCE_MODE, { enabled: true, reason: "Testing" });
        await new Promise(resolve => setTimeout(resolve, 30));
        expect(AuroraClient.maintenanceMode).toBe(true);

        systemEvents.emit(EVENTS.ACTIONS.MAINTENANCE_MODE, { enabled: false });
        await new Promise(resolve => setTimeout(resolve, 30));
        expect(AuroraClient.maintenanceMode).toBe(false);
    });

    /**
     * Test Case: Command Reload
     * Requirement: loadCommands and deployCommands should be called
     */
    test("should reload commands when RELOAD_COMMANDS event is received", async () => {
        const loadSpy = spyOn(AuroraClient, "loadCommands").mockImplementation(() => Promise.resolve());
        const deploySpy = spyOn(AuroraClient, "deployCommands").mockImplementation(() => Promise.resolve());

        systemEvents.emit(EVENTS.ACTIONS.RELOAD_COMMANDS);
        await new Promise(resolve => setTimeout(resolve, 50));

        expect(loadSpy).toHaveBeenCalled();
        expect(deploySpy).toHaveBeenCalled();
    });

    /**
     * Test Case: Cache Clearance
     * Requirement: Service clear methods should be triggered
     */
    test("should trigger service cache clearance when CLEAR_CACHE is received", async () => {
        const { lootdropService } = await import("@shared/modules/economy/lootdrop.service");
        const { tradeService } = await import("@shared/modules/trade/trade.service");

        systemEvents.emit(EVENTS.ACTIONS.CLEAR_CACHE);
        await new Promise(resolve => setTimeout(resolve, 50));

        expect(lootdropService.clearCaches).toHaveBeenCalled();
        expect(tradeService.clearSessions).toHaveBeenCalled();
    });
});
