import { GuildBackupPayloadSchema, type GuildBackupPayload } from '@nexumi/shared';
import { env } from './env';

const DISCORD_API_BASE = 'https://discord.com/api/v10';

async function discordBotFetch<T>(path: string): Promise<T> {
  const response = await fetch(`${DISCORD_API_BASE}${path}`, {
    headers: { Authorization: `Bot ${env.BOT_TOKEN}` },
    cache: 'no-store'
  });
  if (!response.ok) {
    throw new Error(`Discord API request to ${path} failed with status ${response.status}`);
  }
  return (await response.json()) as T;
}

interface DiscordRoleRest {
  id: string;
  name: string;
  color: number;
  hoist: boolean;
  mentionable: boolean;
  permissions: string;
  position: number;
}

interface DiscordOverwriteRest {
  id: string;
  type: number;
  allow: string;
  deny: string;
}

interface DiscordChannelRest {
  id: string;
  name: string;
  type: number;
  parent_id: string | null;
  position: number;
  topic?: string | null;
  nsfw?: boolean;
  rate_limit_per_user?: number;
  bitrate?: number;
  user_limit?: number;
  permission_overwrites?: DiscordOverwriteRest[];
}

interface DiscordGuildRest {
  name: string;
  verification_level: number;
  explicit_content_filter: number;
  default_message_notifications: number;
  afk_timeout: number;
}

/**
 * Builds a guild backup payload via narrow Discord REST calls (bot token,
 * no discord.js Client/gateway). This mirrors
 * `apps/bot/src/modules/guildbackup/service.ts#buildPayloadFromGuild` field
 * for field, since the WebUI process has no live guild cache to read from.
 */
export async function buildGuildBackupPayloadViaRest(guildId: string): Promise<GuildBackupPayload> {
  const [guild, roles, channels] = await Promise.all([
    discordBotFetch<DiscordGuildRest>(`/guilds/${guildId}`),
    discordBotFetch<DiscordRoleRest[]>(`/guilds/${guildId}/roles`),
    discordBotFetch<DiscordChannelRest[]>(`/guilds/${guildId}/channels`)
  ]);

  const payload: GuildBackupPayload = {
    version: 1,
    guildName: guild.name,
    roles: roles
      .slice()
      .sort((a, b) => a.position - b.position)
      .map((role) => ({
        id: role.id,
        name: role.name,
        color: role.color,
        hoist: role.hoist,
        mentionable: role.mentionable,
        permissions: role.permissions,
        position: role.position
      })),
    channels: channels
      .slice()
      .sort((a, b) => {
        if (a.parent_id !== b.parent_id) {
          return (a.parent_id ?? '').localeCompare(b.parent_id ?? '');
        }
        return a.position - b.position;
      })
      .map((channel) => ({
        id: channel.id,
        name: channel.name,
        type: channel.type,
        parentId: channel.parent_id ?? null,
        position: channel.position,
        topic: channel.topic ?? undefined,
        nsfw: channel.nsfw ?? undefined,
        rateLimitPerUser: channel.rate_limit_per_user ?? undefined,
        bitrate: channel.bitrate ?? undefined,
        userLimit: channel.user_limit ?? undefined,
        permissionOverwrites: (channel.permission_overwrites ?? []).map((overwrite) => ({
          id: overwrite.id,
          type: overwrite.type,
          allow: overwrite.allow,
          deny: overwrite.deny
        }))
      })),
    settings: {
      name: guild.name,
      verificationLevel: guild.verification_level,
      explicitContentFilter: guild.explicit_content_filter,
      defaultMessageNotifications: guild.default_message_notifications,
      afkTimeout: guild.afk_timeout
    }
  };

  return GuildBackupPayloadSchema.parse(payload);
}
