import {
  ChannelType,
  EmbedBuilder,
  type Guild,
  type GuildMember,
  type Role,
  type GuildBasedChannel,
  type User
} from 'discord.js';
import { parseDuration } from '../moderation/duration.js';

export class UtilityError extends Error {
  constructor(public readonly code: string) {
    super(code);
    this.name = 'UtilityError';
  }
}

export function parsePollOptions(input: string): string[] {
  const options = input
    .split(',')
    .map((o) => o.trim())
    .filter((o) => o.length > 0);
  if (options.length < 2 || options.length > 5) {
    throw new UtilityError('invalid_poll_options');
  }
  return options;
}

export function parseWhen(input: string): Date {
  const trimmed = input.trim();
  if (/^\d+[smhd]$/i.test(trimmed)) {
    const ms = parseDuration(trimmed);
    return new Date(Date.now() + ms);
  }
  const parsed = Date.parse(trimmed);
  if (Number.isNaN(parsed) || parsed <= Date.now()) {
    throw new UtilityError('invalid_when');
  }
  return new Date(parsed);
}

export function parseTimestampInput(input: string): number {
  const trimmed = input.trim();
  if (/^\d+[smhd]$/i.test(trimmed)) {
    return Date.now() + parseDuration(trimmed);
  }
  const parsed = Date.parse(trimmed);
  if (Number.isNaN(parsed)) {
    throw new UtilityError('invalid_datetime');
  }
  return parsed;
}

export function formatDiscordTimestamps(unixSeconds: number): string {
  return [
    `<t:${unixSeconds}:t>`,
    `<t:${unixSeconds}:T>`,
    `<t:${unixSeconds}:d>`,
    `<t:${unixSeconds}:D>`,
    `<t:${unixSeconds}:f>`,
    `<t:${unixSeconds}:F>`,
    `<t:${unixSeconds}:R>`
  ].join('\n');
}

export function buildUserInfoEmbed(
  user: User,
  member: GuildMember | null,
  locale: 'de' | 'en'
): EmbedBuilder {
  const embed = new EmbedBuilder()
    .setTitle(user.tag)
    .setThumbnail(user.displayAvatarURL({ size: 256 }))
    .setColor(0x6366f1)
    .addFields(
      { name: 'ID', value: user.id, inline: true },
      {
        name: locale === 'de' ? 'Erstellt' : 'Created',
        value: `<t:${Math.floor(user.createdTimestamp / 1000)}:F>`,
        inline: true
      }
    );

  if (member) {
    embed.addFields(
      {
        name: locale === 'de' ? 'Beigetreten' : 'Joined',
        value: member.joinedTimestamp
          ? `<t:${Math.floor(member.joinedTimestamp / 1000)}:F>`
          : '—',
        inline: true
      },
      {
        name: locale === 'de' ? 'Rollen' : 'Roles',
        value:
          member.roles.cache
            .filter((r) => r.id !== member.guild.id)
            .sort((a, b) => b.position - a.position)
            .map((r) => r.toString())
            .slice(0, 15)
            .join(', ') || '—',
        inline: false
      }
    );
  }

  return embed;
}

export function buildServerInfoEmbed(guild: Guild, locale: 'de' | 'en'): EmbedBuilder {
  return new EmbedBuilder()
    .setTitle(guild.name)
    .setThumbnail(guild.iconURL({ size: 256 }))
    .setColor(0x6366f1)
    .addFields(
      { name: 'ID', value: guild.id, inline: true },
      {
        name: locale === 'de' ? 'Mitglieder' : 'Members',
        value: String(guild.memberCount),
        inline: true
      },
      {
        name: locale === 'de' ? 'Erstellt' : 'Created',
        value: guild.createdTimestamp
          ? `<t:${Math.floor(guild.createdTimestamp / 1000)}:F>`
          : '—',
        inline: true
      },
      {
        name: locale === 'de' ? 'Besitzer' : 'Owner',
        value: `<@${guild.ownerId}>`,
        inline: true
      },
      {
        name: locale === 'de' ? 'Boosts' : 'Boosts',
        value: String(guild.premiumSubscriptionCount ?? 0),
        inline: true
      },
      {
        name: locale === 'de' ? 'Kanäle' : 'Channels',
        value: String(guild.channels.cache.size),
        inline: true
      }
    );
}

export function buildRoleInfoEmbed(role: Role, locale: 'de' | 'en'): EmbedBuilder {
  return new EmbedBuilder()
    .setTitle(role.name)
    .setColor(role.color || 0x6366f1)
    .addFields(
      { name: 'ID', value: role.id, inline: true },
      {
        name: locale === 'de' ? 'Mitglieder' : 'Members',
        value: String(role.members.size),
        inline: true
      },
      {
        name: locale === 'de' ? 'Erstellt' : 'Created',
        value: role.createdTimestamp
          ? `<t:${Math.floor(role.createdTimestamp / 1000)}:F>`
          : '—',
        inline: true
      },
      {
        name: locale === 'de' ? 'Farbe' : 'Color',
        value: role.hexColor,
        inline: true
      },
      {
        name: locale === 'de' ? 'Position' : 'Position',
        value: String(role.position),
        inline: true
      },
      {
        name: locale === 'de' ? 'Erwähnbar' : 'Mentionable',
        value: role.mentionable ? '✓' : '✗',
        inline: true
      }
    );
}

export function buildChannelInfoEmbed(
  channel: GuildBasedChannel,
  locale: 'de' | 'en'
): EmbedBuilder {
  const typeLabel =
    channel.type === ChannelType.GuildText
      ? locale === 'de'
        ? 'Text'
        : 'Text'
      : channel.type === ChannelType.GuildVoice
        ? locale === 'de'
          ? 'Voice'
          : 'Voice'
        : String(channel.type);

  const embed = new EmbedBuilder()
    .setTitle(channel.name)
    .setColor(0x6366f1)
    .addFields(
      { name: 'ID', value: channel.id, inline: true },
      { name: locale === 'de' ? 'Typ' : 'Type', value: typeLabel, inline: true },
      {
        name: locale === 'de' ? 'Erstellt' : 'Created',
        value: channel.createdTimestamp
          ? `<t:${Math.floor(channel.createdTimestamp / 1000)}:F>`
          : '—',
        inline: true
      }
    );

  if ('topic' in channel && channel.topic) {
    embed.addFields({
      name: locale === 'de' ? 'Thema' : 'Topic',
      value: channel.topic.slice(0, 1024),
      inline: false
    });
  }

  return embed;
}

export function parseHexColor(input: string): number | null {
  const cleaned = input.replace(/^#/, '').trim();
  if (!/^[0-9a-fA-F]{6}$/.test(cleaned)) {
    return null;
  }
  return Number.parseInt(cleaned, 16);
}

export const CUSTOM_EMOJI_REGEX = /<a?:(\w+):(\d+)>/;

export function extractFirstCustomEmoji(content: string): { name: string; id: string } | null {
  const match = content.match(CUSTOM_EMOJI_REGEX);
  if (!match) {
    return null;
  }
  return { name: match[1], id: match[2] };
}
