import { ChatInputCommandInteraction, GuildMember, SlashCommandBuilder } from 'discord.js';
import { SupportedLocale, t } from '../i18n';
import { MusicService } from '../services/MusicService';
import { logger } from '../utils/logger';

function buildErrorMessage(locale: SupportedLocale, key: string) {
  const message = t(locale, `commands.music.${key}`);
  const resolution = t(locale, `commands.music.${key}Resolution`);
  return resolution && resolution !== `commands.music.${key}Resolution`
    ? `${message}\n${resolution}`
    : message;
}

async function respond(
  interaction: ChatInputCommandInteraction,
  content: string,
  ephemeral = false,
) {
  if (interaction.deferred) {
    await interaction.editReply({ content });
    return;
  }

  if (interaction.replied) {
    await interaction.followUp({ content, ephemeral });
    return;
  }

  await interaction.editReply({ content });
}

export default {
  data: new SlashCommandBuilder()
    .setName('music')
    .setDescription('Play YouTube audio in voice channels.')
    .setDescriptionLocalizations({
      ko: '음성 채널에서 YouTube 오디오를 재생합니다.',
    })
    .addSubcommand((subcommand) =>
      subcommand
        .setName('add')
        .setDescription('Search YouTube or add a video URL to the queue.')
        .setDescriptionLocalizations({
          ko: 'YouTube를 검색하거나 영상 URL을 재생 목록에 추가합니다.',
        })
        .addStringOption((option) =>
          option
            .setName('query')
            .setDescription('Search query for YouTube')
            .setDescriptionLocalizations({
              ko: 'YouTube 검색어',
            }),
        )
        .addStringOption((option) =>
          option
            .setName('url')
            .setDescription('YouTube video URL')
            .setDescriptionLocalizations({
              ko: 'YouTube 영상 URL',
            }),
        ),
    )
    .addSubcommand((subcommand) =>
      subcommand
        .setName('queue')
        .setDescription('Show the current music queue.')
        .setDescriptionLocalizations({
          ko: '현재 음악 재생 목록을 표시합니다.',
        }),
    )
    .addSubcommand((subcommand) =>
      subcommand
        .setName('remove')
        .setDescription('Remove a track from the upcoming queue.')
        .setDescriptionLocalizations({
          ko: '대기열에서 원하는 곡을 삭제합니다.',
        })
        .addIntegerOption((option) =>
          option
            .setName('index')
            .setDescription('Queue index to remove')
            .setDescriptionLocalizations({
              ko: '삭제할 대기열 인덱스',
            })
            .setRequired(true)
            .setMinValue(1),
        ),
    )
    .addSubcommand((subcommand) =>
      subcommand
        .setName('pause')
        .setDescription('Pause the currently playing track.')
        .setDescriptionLocalizations({
          ko: '현재 재생 중인 곡을 일시정지합니다.',
        }),
    )
    .addSubcommand((subcommand) =>
      subcommand
        .setName('resume')
        .setDescription('Resume the paused track.')
        .setDescriptionLocalizations({
          ko: '일시정지된 곡의 재생을 다시 시작합니다.',
        }),
    )
    .addSubcommand((subcommand) =>
      subcommand
        .setName('skip')
        .setDescription('Skip the currently playing track.')
        .setDescriptionLocalizations({
          ko: '현재 재생 중인 곡을 건너뜁니다.',
        }),
    )
    .addSubcommand((subcommand) =>
      subcommand
        .setName('stop')
        .setDescription('Stop playback and clear the queue.')
        .setDescriptionLocalizations({
          ko: '재생을 중지하고 대기열을 비웁니다.',
        }),
    )
    .addSubcommand((subcommand) =>
      subcommand
        .setName('leave')
        .setDescription('Disconnect the bot from the voice channel.')
        .setDescriptionLocalizations({
          ko: '봇을 음성 채널에서 내보냅니다.',
        }),
    ),

  async execute(interaction: ChatInputCommandInteraction, locale: SupportedLocale) {
    const subcommand = interaction.options.getSubcommand();

    try {
      if (subcommand === 'add') {
        const query = interaction.options.getString('query');
        const url = interaction.options.getString('url');

        if ((!query && !url) || (query && url)) {
          await interaction.editReply({
            content: buildErrorMessage(locale, 'addMutuallyExclusive'),
          });
          return;
        }

        const member = interaction.member as GuildMember;
        if (!member.voice.channel) {
          await interaction.editReply({
            content: buildErrorMessage(locale, 'notInVoice'),
          });
          return;
        }

        const textChannel = interaction.channel as any;
        if (!textChannel?.send) {
          await interaction.editReply({
            content: t(locale, 'errors.E3003.userMessage'),
          });
          return;
        }

        const result = query
          ? await MusicService.addFromQuery(member, textChannel, query, locale)
          : await MusicService.addFromUrl(member, textChannel, url!, locale);

        await interaction.editReply({
          content: result.tracksAdded > 1
            ? (result.startedNow
              ? t(locale, 'commands.music.playlistAddedNowPlaying', {
                  count: String(result.tracksAdded),
                  channel: `<#${result.voiceChannelId}>`,
                })
              : t(locale, 'commands.music.playlistAddedLater', {
                  count: String(result.tracksAdded),
                }))
            : (result.startedNow
              ? t(locale, 'commands.music.queueAddedNowPlaying', {
                  title: result.track.title,
                  channel: `<#${result.voiceChannelId}>`,
                })
              : t(locale, 'commands.music.queueAddedLater', {
                  title: result.track.title,
                  position: String(result.position),
                })),
        });
        return;
      }

      if (subcommand === 'queue') {
        await interaction.editReply({
          embeds: [MusicService.getQueueEmbed(interaction.guildId!, locale)],
        });
        return;
      }

      if (subcommand === 'remove') {
        const member = interaction.member as GuildMember;
        if (!member.voice.channel) {
          await interaction.editReply({
            content: buildErrorMessage(locale, 'notInVoice'),
          });
          return;
        }

        const activeVoiceChannelId = MusicService.getActiveVoiceChannelId(interaction.guildId!);
        if (activeVoiceChannelId && activeVoiceChannelId !== member.voice.channelId) {
          await interaction.editReply({
            content: buildErrorMessage(locale, 'differentVoiceChannel'),
          });
          return;
        }

        const index = interaction.options.getInteger('index', true);
        const removed = await MusicService.remove(interaction.guildId!, index);
        if (!removed) {
          await interaction.editReply({
            content: buildErrorMessage(locale, 'noActiveSession'),
          });
          return;
        }

        await interaction.editReply({
          content: t(locale, 'commands.music.queueRemoved', {
            title: removed.title,
          }),
        });
        return;
      }

      if (subcommand === 'pause') {
        const member = interaction.member as GuildMember;
        if (!member.voice.channel) {
          await interaction.editReply({
            content: buildErrorMessage(locale, 'notInVoice'),
          });
          return;
        }

        const activeVoiceChannelId = MusicService.getActiveVoiceChannelId(interaction.guildId!);
        if (activeVoiceChannelId && activeVoiceChannelId !== member.voice.channelId) {
          await interaction.editReply({
            content: buildErrorMessage(locale, 'differentVoiceChannel'),
          });
          return;
        }

        const paused = await MusicService.pause(interaction.guildId!, locale);
        if (!paused) {
          await interaction.editReply({
            content: buildErrorMessage(locale, 'noActiveSession'),
          });
          return;
        }

        await interaction.editReply({ content: t(locale, 'commands.music.pauseSuccess') });
        return;
      }

      if (subcommand === 'resume') {
        const member = interaction.member as GuildMember;
        if (!member.voice.channel) {
          await interaction.editReply({
            content: buildErrorMessage(locale, 'notInVoice'),
          });
          return;
        }

        const activeVoiceChannelId = MusicService.getActiveVoiceChannelId(interaction.guildId!);
        if (activeVoiceChannelId && activeVoiceChannelId !== member.voice.channelId) {
          await interaction.editReply({
            content: buildErrorMessage(locale, 'differentVoiceChannel'),
          });
          return;
        }

        const resumed = await MusicService.resume(interaction.guildId!, locale);
        if (!resumed) {
          await interaction.editReply({
            content: buildErrorMessage(locale, 'noActiveSession'),
          });
          return;
        }

        await interaction.editReply({ content: t(locale, 'commands.music.resumeSuccess') });
        return;
      }

      if (subcommand === 'skip') {
        const member = interaction.member as GuildMember;
        if (!member.voice.channel) {
          await interaction.editReply({
            content: buildErrorMessage(locale, 'notInVoice'),
          });
          return;
        }

        const activeVoiceChannelId = MusicService.getActiveVoiceChannelId(interaction.guildId!);
        if (activeVoiceChannelId && activeVoiceChannelId !== member.voice.channelId) {
          await interaction.editReply({
            content: buildErrorMessage(locale, 'differentVoiceChannel'),
          });
          return;
        }

        const skipped = await MusicService.skip(interaction.guildId!);
        if (!skipped) {
          await interaction.editReply({
            content: buildErrorMessage(locale, 'noActiveSession'),
          });
          return;
        }

        await interaction.editReply({ content: t(locale, 'commands.music.skipSuccess') });
        return;
      }

      if (subcommand === 'stop') {
        const member = interaction.member as GuildMember;
        if (!member.voice.channel) {
          await interaction.editReply({
            content: buildErrorMessage(locale, 'notInVoice'),
          });
          return;
        }

        const activeVoiceChannelId = MusicService.getActiveVoiceChannelId(interaction.guildId!);
        if (activeVoiceChannelId && activeVoiceChannelId !== member.voice.channelId) {
          await interaction.editReply({
            content: buildErrorMessage(locale, 'differentVoiceChannel'),
          });
          return;
        }

        const stopped = await MusicService.stop(interaction.guildId!, locale);
        if (!stopped) {
          await interaction.editReply({
            content: buildErrorMessage(locale, 'noActiveSession'),
          });
          return;
        }

        await interaction.editReply({ content: t(locale, 'commands.music.stopSuccess') });
        return;
      }

      if (subcommand === 'leave') {
        const member = interaction.member as GuildMember;
        if (!member.voice.channel) {
          await interaction.editReply({
            content: buildErrorMessage(locale, 'notInVoice'),
          });
          return;
        }

        const activeVoiceChannelId = MusicService.getActiveVoiceChannelId(interaction.guildId!);
        if (activeVoiceChannelId && activeVoiceChannelId !== member.voice.channelId) {
          await interaction.editReply({
            content: buildErrorMessage(locale, 'differentVoiceChannel'),
          });
          return;
        }

        const left = await MusicService.leave(interaction.guildId!, locale);
        if (!left) {
          await interaction.editReply({
            content: buildErrorMessage(locale, 'noActiveSession'),
          });
          return;
        }

        await interaction.editReply({ content: t(locale, 'commands.music.leaveSuccess') });
      }
    } catch (error) {
      logger.error('Error in music command:', error);

      const knownError = error instanceof Error ? error.message : '';
      if (knownError === 'NOT_IN_VOICE') {
        await respond(interaction, buildErrorMessage(locale, 'notInVoice'), true);
        return;
      }
      if (knownError === 'DIFFERENT_VOICE') {
        await respond(interaction, buildErrorMessage(locale, 'differentVoiceChannel'), true);
        return;
      }
      if (knownError === 'NO_SEARCH_RESULTS') {
        await respond(interaction, buildErrorMessage(locale, 'noSearchResults'), true);
        return;
      }
      if (knownError === 'INVALID_URL') {
        await respond(interaction, buildErrorMessage(locale, 'invalidUrl'), true);
        return;
      }
      if (knownError === 'QUEUE_INDEX_OUT_OF_RANGE') {
        await respond(interaction, buildErrorMessage(locale, 'queueRemoveOutOfRange'), true);
        return;
      }

      await respond(interaction, t(locale, 'errors.E3003.userMessage'), true);
    }
  },
};
