import type { GuildMember, InteractionReplyOptions, Message, MessageCreateOptions } from "discord.js";
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";

import {
  formatTeamMessages,
  makeTeams,
  MAX_TEAM_SIZE,
  MIN_TEAM_SIZE,
  parseTeamSize,
  TEAM_COMMAND_NAME,
  TEAM_SIZE_OPTION_NAME,
} from "../commands/team.js";

export const teamSlashCommand = new SlashCommandBuilder()
  .setName(TEAM_COMMAND_NAME)
  .setDescription("현재 음성 채널의 사람들을 무작위로 팀에 배정합니다.")
  .setDMPermission(false)
  .addIntegerOption((option) =>
    option
      .setName(TEAM_SIZE_OPTION_NAME)
      .setDescription("한 팀에 들어갈 최대 인원")
      .setMinValue(MIN_TEAM_SIZE)
      .setMaxValue(MAX_TEAM_SIZE)
      .setRequired(true),
  );

interface TeamResult {
  messages: string[];
  participantIds: string[];
}

function createTeamsForMember(member: GuildMember, teamSize: number): TeamResult | string {
  const voiceChannel = member.voice.channel;

  if (!voiceChannel) {
    return "먼저 팀을 나눌 음성 채널에 들어가 주세요.";
  }

  const participants = [...voiceChannel.members.values()].filter(
    (participant) => !participant.user.bot,
  );

  if (participants.length === 0) {
    return "현재 음성 채널에 팀을 나눌 사람이 없습니다.";
  }

  const teams = makeTeams(participants, teamSize);

  return {
    messages: formatTeamMessages(teams),
    participantIds: participants.map((participant) => participant.id),
  };
}

export async function handleTeamInteraction(
  interaction: ChatInputCommandInteraction,
): Promise<void> {
  if (interaction.commandName !== TEAM_COMMAND_NAME) {
    return;
  }

  if (!interaction.inCachedGuild()) {
    await interaction.reply({ content: "서버 안에서만 사용할 수 있는 명령입니다.", ephemeral: true });
    return;
  }

  const teamSize = interaction.options.getInteger(TEAM_SIZE_OPTION_NAME, true);
  const result = createTeamsForMember(interaction.member, teamSize);

  if (typeof result === "string") {
    await interaction.reply({ content: result, ephemeral: true });
    return;
  }

  const allowedMentions = { users: result.participantIds };
  const [firstMessage, ...remainingMessages] = result.messages;

  if (!firstMessage) {
    await interaction.reply({ content: "팀을 만들지 못했습니다.", ephemeral: true });
    return;
  }

  await interaction.reply({ content: firstMessage, allowedMentions } satisfies InteractionReplyOptions);

  for (const content of remainingMessages) {
    await interaction.followUp({ content, allowedMentions });
  }
}

export async function handleTeamMessage(message: Message<true>, prefix: string): Promise<void> {
  const command = `${prefix}${TEAM_COMMAND_NAME}`;
  const content = message.content.trim();

  if (content !== command && !content.startsWith(`${command} `) && !content.startsWith(`${command}\t`)) {
    return;
  }

  const argumentsText = content.slice(command.length).trim();
  const argumentsList = argumentsText ? argumentsText.split(/\s+/) : [];
  const teamSize = argumentsList.length === 1 ? parseTeamSize(argumentsList[0]) : null;

  if (teamSize === null) {
    await message.reply({
      content: `사용법: \`${command} 4\` (팀 인원은 ${MIN_TEAM_SIZE}~${MAX_TEAM_SIZE}명)`,
      allowedMentions: { repliedUser: false },
    });
    return;
  }

  if (!message.member) {
    await message.reply({
      content: "서버 멤버 정보를 확인하지 못했습니다. 잠시 후 다시 시도해 주세요.",
      allowedMentions: { repliedUser: false },
    });
    return;
  }

  const result = createTeamsForMember(message.member, teamSize);

  if (typeof result === "string") {
    await message.reply({ content: result, allowedMentions: { repliedUser: false } });
    return;
  }

  const allowedMentions = { users: result.participantIds, repliedUser: false };
  const [firstMessage, ...remainingMessages] = result.messages;

  if (!firstMessage) {
    return;
  }

  await message.reply({ content: firstMessage, allowedMentions } satisfies MessageCreateOptions);

  for (const followUp of remainingMessages) {
    await message.channel.send({ content: followUp, allowedMentions });
  }
}
