import { Client as DiscordClient, Collection, GatewayIntentBits, REST, Routes, MessageFlags } from "discord.js";
import { join } from "node:path";
import type { Command } from "@shared/lib/types";
import { env } from "@shared/lib/env";
import { CommandLoader } from "@lib/loaders/CommandLoader";
import { EventLoader } from "@lib/loaders/EventLoader";

export class Client extends DiscordClient {

    commands: Collection<string, Command>;
    knownCommands: Map<string, string>;
    lastCommandTimestamp: number | null = null;
    maintenanceMode: boolean = false;
    private commandLoader: CommandLoader;
    private eventLoader: EventLoader;

    constructor({ intents }: { intents: number[] }) {
        super({ intents });
        this.commands = new Collection<string, Command>();
        this.knownCommands = new Map<string, string>();
        this.commandLoader = new CommandLoader(this);
        this.eventLoader = new EventLoader(this);
    }

    public async setupSystemEvents() {
        const { systemEvents, EVENTS } = await import("@shared/lib/events");

        systemEvents.on(EVENTS.ACTIONS.RELOAD_COMMANDS, async () => {
            console.log("🔄 System Action: Reloading commands...");
            try {
                await this.loadCommands(true);
                await this.deployCommands();

                const { dashboardService } = await import("@shared/modules/dashboard/dashboard.service");
                await dashboardService.recordEvent({
                    type: "success",
                    message: "Bot: Commands reloaded and redeployed",
                    icon: "✅"
                });
            } catch (error) {
                console.error("Failed to reload commands:", error);
            }
        });

        systemEvents.on(EVENTS.ACTIONS.CLEAR_CACHE, async () => {
            console.log("� System Action: Clearing all internal caches...");

            try {
                // 1. Lootdrop Service
                const { lootdropService } = await import("@shared/modules/economy/lootdrop.service");
                await lootdropService.clearCaches();

                // 2. Trade Service
                const { tradeService } = await import("@shared/modules/trade/trade.service");
                tradeService.clearSessions();

                // 3. Item Wizard
                const { clearDraftSessions } = await import("@/modules/admin/item_wizard");
                clearDraftSessions();

                const { dashboardService } = await import("@shared/modules/dashboard/dashboard.service");
                await dashboardService.recordEvent({
                    type: "success",
                    message: "Bot: All internal caches and sessions cleared",
                    icon: "🧼"
                });
            } catch (error) {
                console.error("Failed to clear caches:", error);
            }
        });

        systemEvents.on(EVENTS.ACTIONS.MAINTENANCE_MODE, async (data: { enabled: boolean, reason?: string }) => {
            const { enabled, reason } = data;
            console.log(`🛠️ System Action: Maintenance mode ${enabled ? "ON" : "OFF"}${reason ? ` (${reason})` : ""}`);
            this.maintenanceMode = enabled;
        });

        systemEvents.on(EVENTS.QUEST.COMPLETED, async (data: { userId: string, quest: any, rewards: any }) => {
            const { userId, quest, rewards } = data;
            try {
                const user = await this.users.fetch(userId);
                if (!user) return;

                const { getQuestCompletionComponents } = await import("@/modules/quest/quest.view");
                const components = getQuestCompletionComponents(quest, rewards);

                // Try to send to the user's DM
                await user.send({ 
                    components: components as any,
                    flags: [MessageFlags.IsComponentsV2]
                }).catch(async () => {
                    console.warn(`Could not DM user ${userId} quest completion message. User might have DMs disabled.`);
                });
            } catch (error) {
                console.error("Failed to send quest completion notification:", error);
            }
        });
    }

    async loadCommands(reload: boolean = false) {
        if (reload) {
            this.commands.clear();
            this.knownCommands.clear();
            console.log("♻️  Reloading commands...");
        }

        const commandsPath = join(import.meta.dir, '../commands');
        const result = await this.commandLoader.loadFromDirectory(commandsPath, reload);

        console.log(`📦 Command loading complete: ${result.loaded} loaded, ${result.skipped} skipped, ${result.errors.length} errors`);
    }

    async loadEvents(reload: boolean = false) {
        if (reload) {
            this.removeAllListeners();
            console.log("♻️  Reloading events...");
        }

        const eventsPath = join(import.meta.dir, '../events');
        const result = await this.eventLoader.loadFromDirectory(eventsPath, reload);

        console.log(`📦 Event loading complete: ${result.loaded} loaded, ${result.skipped} skipped, ${result.errors.length} errors`);
    }



    async deployCommands() {
        // We use env.DISCORD_BOT_TOKEN directly so this can run without client.login()
        const token = env.DISCORD_BOT_TOKEN;
        if (!token) {
            console.error("DISCORD_BOT_TOKEN is not set.");
            return;
        }

        const rest = new REST().setToken(token);
        const commandsData = this.commands.map(c => c.data.toJSON());
        const guildId = env.DISCORD_GUILD_ID;
        const clientId = env.DISCORD_CLIENT_ID;

        if (!clientId) {
            console.error("DISCORD_CLIENT_ID is not set.");
            return;
        }

        try {
            console.log(`Started refreshing ${commandsData.length} application (/) commands.`);

            let data;
            if (guildId) {
                console.log(`Registering commands to guild: ${guildId}`);
                data = await rest.put(
                    Routes.applicationGuildCommands(clientId, guildId),
                    { body: commandsData },
                );
                // Clear global commands to avoid duplicates
                await rest.put(Routes.applicationCommands(clientId), { body: [] });
            } else {
                console.log('Registering commands globally');
                data = await rest.put(
                    Routes.applicationCommands(clientId),
                    { body: commandsData },
                );
            }

            console.log(`Successfully reloaded ${(data as any).length} application (/) commands.`);
        } catch (error: any) {
            if (error.code === 50001) {
                console.warn("Missing Access: The bot is not in the guild or lacks 'applications.commands' scope.");
                console.warn("   If you are testing locally, make sure you invited the bot with scope 'bot applications.commands'.");
            } else {
                console.error(error);
            }
        }
    }

    async shutdown() {
        const { setShuttingDown, waitForTransactions } = await import("./shutdown");
        const { closeDatabase } = await import("@shared/db/DrizzleClient");

        console.log("🛑 Shutdown signal received. Starting graceful shutdown...");
        setShuttingDown(true);

        // Wait for transactions to complete
        console.log("⏳ Waiting for active transactions to complete...");
        await waitForTransactions(10000);

        // Destroy Discord client
        console.log("🔌 Disconnecting from Discord...");
        this.destroy();

        // Close database
        console.log("🗄️ Closing database connection...");
        await closeDatabase();

        console.log("👋 Graceful shutdown complete. Exiting.");
        process.exit(0);
    }
}

export const AuroraClient = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.MessageContent, GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildMembers, GatewayIntentBits.DirectMessages] });