import { ActivityType, Events, GatewayIntentBits } from "discord.js";
import { DiscordClient } from "./client";
import { readCommands } from "./commands";
import { registerCommands } from "./commands/register";
import { setSleepTimer, startTimer } from "./utils";

let wakeUpInterval: Timer;

// create a new Client instance
const client = new DiscordClient({
  intents: [
    GatewayIntentBits.MessageContent,
    GatewayIntentBits.Guilds,
    GatewayIntentBits.DirectMessages,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.GuildModeration,
  ],
});

// listen for the client to be ready
client.once(Events.ClientReady, async (c) => {
  console.log(`Ready! Logged in as ${c.user.tag}`);
  const commands = await readCommands();

  commands.forEach((command) => {
    client.commands.set(command.data.name, command);
  });
  await registerCommands(commands, c.user.id);
  startTimer(client, 5 * 1000);
  console.log("timer started");
});

client.on(Events.MessageCreate, async (message) => {
  if (message.author.id === client.user?.id) return;
  if (
    message.mentions.has(client.user!.id) ||
    message.content.toLowerCase().includes("joel")
  ) {
    message.channel.sendTyping();

    let reference: string | undefined;
    if (message.reference) {
      const referenceMessage = await message.fetchReference();
      reference = referenceMessage.content
        .replace(/<@!?(\d+)>/g, (match, id) => {
          const user = message.guild?.members.cache.get(id);
          return user ? user.displayName : match;
        })
        .trim();
    }

    // convert mentions to regular text
    const content = message.content
      .replace(/<@!?(\d+)>/g, (match, id) => {
        const user = message.guild?.members.cache.get(id);
        return user ? user.displayName : match;
      })
      .trim();

    try {
      const response = await client.ai.ask(
        content,
        message.author.username,
        reference
      );
      const text = response.choices[0].message.content;
      // if message is longer than 2000 characters, send it in chunks
      const slices = text?.replace("\n\n", "\n").match(/.{1,2000}/gs) || [
        "🟥 There was an error while processing this message!",
      ];

      slices.forEach(async (slice, index) => {
        if (index === 0) {
          await message.reply({
            content: slice,
          });
        } else {
          await message.channel.send({
            content: slice,
          });
        }
      });
      setSleepTimer(client);
    } catch (error) {
      startTimer(client, 5 * 1000);

      await message.reply({
        content: "🟥 Joel fucking sover! Ge honom en minut eller två",
      });
    }
  }
});

client.on(Events.InteractionCreate, async (interaction) => {
  if (!interaction.isChatInputCommand()) return;

  console.log(interaction.commandName);

  const command = client.commands.get(interaction.commandName);

  if (!command) {
    console.error(`No command matching ${interaction.commandName} was found.`);
    return;
  }

  try {
    await command.execute(interaction);
  } catch (error) {
    console.error(error);
    if (interaction.replied || interaction.deferred) {
      await interaction.followUp({
        content: "There was an error while executing this command!",
        ephemeral: true,
      });
    } else {
      await interaction.reply({
        content: "There was an error while executing this command!",
        ephemeral: true,
      });
    }
  }
});

// login with the token from .env.local
client.login(process.env.DISCORD_TOKEN);
