import { PermissionFlagsBits } from 'discord.js';
import { t, tf } from '@nexumi/shared';
import type { SlashCommand } from '../../types.js';
import { getGuildLocale } from '../../i18n.js';
import { requirePermission } from '../../permissions.js';
import { birthdayCommandData } from './command-definitions.js';
import {
  BirthdaySetSchema,
  daysUntilBirthday,
  getBirthdayConfig,
  isValidTimezone,
  listBirthdays,
  removeBirthday,
  setBirthday,
  updateBirthdayConfig
} from './service.js';

const birthdayCommand: SlashCommand = {
  data: birthdayCommandData,
  async execute(interaction, context) {
    const locale = await getGuildLocale(context.prisma, interaction.guildId);
    if (!interaction.inGuild()) {
      await interaction.reply({ content: t(locale, 'generic.guildOnly'), ephemeral: true });
      return;
    }

    const guildId = interaction.guildId!;
    const sub = interaction.options.getSubcommand();

    if (sub === 'setup') {
      if (!(await requirePermission(interaction, PermissionFlagsBits.ManageGuild, locale))) {
        return;
      }

      const channel = interaction.options.getChannel('channel', true);
      const role = interaction.options.getRole('role');
      const timezone = interaction.options.getString('timezone') ?? 'Europe/Berlin';
      const message = interaction.options.getString('message');

      if (!isValidTimezone(timezone)) {
        await interaction.reply({ content: t(locale, 'birthdays.error.invalidTimezone'), ephemeral: true });
        return;
      }

      await updateBirthdayConfig(context.prisma, guildId, {
        enabled: true,
        channelId: channel.id,
        roleId: role?.id ?? null,
        message: message ?? null,
        timezone
      });

      await interaction.reply({ content: t(locale, 'birthdays.setup.done'), ephemeral: true });
      return;
    }

    const config = await getBirthdayConfig(context.prisma, guildId);

    if (sub === 'set') {
      const month = interaction.options.getInteger('month', true);
      const day = interaction.options.getInteger('day', true);
      const year = interaction.options.getInteger('year') ?? undefined;
      const parsed = BirthdaySetSchema.safeParse({ month, day, year });

      if (!parsed.success) {
        await interaction.reply({ content: t(locale, 'birthdays.error.invalidDate'), ephemeral: true });
        return;
      }

      try {
        await setBirthday(context.prisma, guildId, interaction.user.id, parsed.data);
      } catch (error) {
        if (error instanceof Error && error.message === 'invalid_date') {
          await interaction.reply({ content: t(locale, 'birthdays.error.invalidDate'), ephemeral: true });
          return;
        }
        throw error;
      }

      await interaction.reply({
        content: tf(locale, 'birthdays.set.success', { month, day, year: year ?? '—' }),
        ephemeral: true
      });
      return;
    }

    if (sub === 'remove') {
      const removed = await removeBirthday(context.prisma, guildId, interaction.user.id);
      if (!removed) {
        await interaction.reply({ content: t(locale, 'birthdays.remove.none'), ephemeral: true });
        return;
      }
      await interaction.reply({ content: t(locale, 'birthdays.remove.success'), ephemeral: true });
      return;
    }

    if (sub === 'list' || sub === 'next') {
      const entries = await listBirthdays(context.prisma, guildId, config.timezone);
      if (entries.length === 0) {
        await interaction.reply({ content: t(locale, 'birthdays.list.empty'), ephemeral: true });
        return;
      }

      const slice = sub === 'next' ? entries.slice(0, 10) : entries.slice(0, 25);
      const lines = slice.map((entry, index) => {
        const days = daysUntilBirthday(entry.month, entry.day, config.timezone);
        const dateLabel = `${String(entry.day).padStart(2, '0')}.${String(entry.month).padStart(2, '0')}`;
        const yearLabel = entry.year ? ` (${entry.year})` : '';
        return tf(locale, 'birthdays.list.line', {
          rank: index + 1,
          user: `<@${entry.userId}>`,
          date: `${dateLabel}${yearLabel}`,
          days
        });
      });

      const header = t(locale, sub === 'next' ? 'birthdays.next.header' : 'birthdays.list.header');
      await interaction.reply({
        content: `${header}\n${lines.join('\n')}`,
        ephemeral: true
      });
    }
  }
};

export const birthdayCommands: SlashCommand[] = [birthdayCommand];
