import { REST, Routes, APIApplicationCommand } from "discord.js";
import fs from "node:fs";
import path from "node:path";
import logger from "./src/utils/logger.js"; // Added .js extension for ES modules
import dotenv from "dotenv";

// --- Setup ---
dotenv.config(); // Load .env variables

// Log presence of required env vars (optional, but helpful for debugging)
// logger.info(`CLIENT_ID: ${process.env.CLIENT_ID ? 'Present' : 'MISSING!'}`);
// logger.info(`DISCORD_TOKEN: ${process.env.DISCORD_TOKEN ? 'Present' : 'MISSING!'}`);

// --- Configuration ---
const clientId = process.env.CLIENT_ID;
const token = process.env.DISCORD_TOKEN;

if (!clientId || !token) {
  logger.error("Missing CLIENT_ID or DISCORD_TOKEN in .env file for command deployment!");
  process.exit(1);
}

const commands: Omit<APIApplicationCommand, "id" | "application_id" | "version">[] = []; // Type the commands array more accurately
// Grab all the command files from the commands directory
const commandsPath = path.join(__dirname, "src", "commands");
// Read .ts files now
const commandFiles = fs.readdirSync(commandsPath).filter((file: string) => file.endsWith(".ts")); // Add string type

// Grab the SlashCommandBuilder#toJSON() output of each command's data for deployment
logger.info(`Started loading ${commandFiles.length} application (/) commands for deployment.`);

const loadCommandsForDeployment = async () => {
  for (const file of commandFiles) {
    const filePath = path.join(commandsPath, file);
    try {
      // Use dynamic import with file:// protocol for ES modules
      const fileUrl = new URL(`file://${filePath}`);
      const commandModule = await import(fileUrl.href);
      // Assuming commands export default or have a 'default' property
      const command = commandModule.default || commandModule;

      if (
        command &&
        typeof command === "object" &&
        "data" in command &&
        typeof command.data.toJSON === "function"
      ) {
        // We push the JSON representation which matches the API structure
        commands.push(command.data.toJSON());
        logger.info(`Loaded command for deployment: ${command.data.name}`);
      } else {
        logger.warn(
          `[WARNING] The command at ${filePath} is missing a required "data" property with a "toJSON" method.`,
        );
      }
    } catch (error: unknown) {
      // Type error as unknown
      const errorMessage = error instanceof Error ? error.message : String(error);
      logger.error(`Error loading command at ${filePath} for deployment: ${errorMessage}`, error);
    }
  }
};

// Construct and prepare an instance of the REST module
const rest = new REST({ version: "10" }).setToken(token);

// Define the deployment function
const deployCommands = async () => {
  try {
    await loadCommandsForDeployment(); // Wait for commands to be loaded

    if (commands.length === 0) {
      logger.warn("No commands loaded for deployment. Exiting.");
      return;
    }

    logger.info(`Started refreshing ${commands.length} application (/) commands.`);

    // The put method is used to fully refresh all commands
    const guildId = process.env.GUILD_ID;
    let data: any; // Type appropriately if possible, depends on discord.js version

    if (guildId) {
      // Deploying to a specific guild (faster for testing)
      logger.info(`Deploying commands to guild: ${guildId}`);
      data = await rest.put(Routes.applicationGuildCommands(clientId, guildId), { body: commands });
      logger.info(
        `Successfully reloaded ${data.length} application (/) commands in guild ${guildId}.`,
      );
    } else {
      // Deploying globally (can take up to an hour)
      logger.info("Deploying commands globally...");
      data = await rest.put(Routes.applicationCommands(clientId), { body: commands });
      logger.info(`Successfully reloaded ${data.length} global application (/) commands.`);
    }
  } catch (error: unknown) {
    // Type error as unknown
    const errorMessage = error instanceof Error ? error.message : String(error);
    logger.error(`Failed during command deployment: ${errorMessage}`, error);
  }
};

// Execute the deployment
deployCommands();

// Note: The old wipe logic is removed as PUT overwrites existing commands.
// If you specifically need to wipe commands first for some reason,
// you can add separate PUT requests with an empty body before deploying.
