"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.fetchUserData = fetchUserData;
const node_fetch_1 = __importStar(require("node-fetch"));
const errors_1 = require("../errors");
const badges_1 = require("../utils/badges");
const DISCORD_API = 'https://discord.com/api/v10';
const DISCORD_CDN = 'https://cdn.discordapp.com';
const MAX_RETRIES = 3;
const BASE_DELAY_MS = 500;
const RETRYABLE_CODES = new Set([429, 502, 503, 504]);
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
function getAvatarURL(userId, avatarHash) {
    if (!avatarHash) {
        return `${DISCORD_CDN}/embed/avatars/${Number.parseInt(userId, 10) % 5}.png`;
    }
    const extension = avatarHash.startsWith('a_') ? 'gif' : 'png';
    return `${DISCORD_CDN}/avatars/${userId}/${avatarHash}.${extension}`;
}
function getBannerURL(userId, bannerHash) {
    if (!bannerHash)
        return null;
    const extension = bannerHash.startsWith('a_') ? 'gif' : 'png';
    return `${DISCORD_CDN}/banners/${userId}/${bannerHash}.${extension}`;
}
function getAvatarDecorationURL(decorationData) {
    if (!decorationData?.asset)
        return null;
    return `${DISCORD_CDN}/avatar-decoration-presets/${decorationData.asset}.png`;
}
async function fetchUserData(userId, botToken) {
    if (!botToken || typeof botToken !== 'string') {
        throw new errors_1.KythiaArtsError('Bot token is required to fetch data from Discord API');
    }
    let lastError = null;
    for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
        try {
            const response = await (0, node_fetch_1.default)(`${DISCORD_API}/users/${userId}`, {
                headers: {
                    Authorization: `Bot ${botToken}`,
                    'Content-Type': 'application/json',
                },
            });
            if (!response.ok) {
                if (response.status === 401) {
                    throw new errors_1.KythiaArtsError('Invalid bot token');
                }
                if (response.status === 404) {
                    throw new errors_1.KythiaArtsError('User not found');
                }
                if (RETRYABLE_CODES.has(response.status)) {
                    const retryAfterHeader = response.headers.get('retry-after');
                    const delayMs = retryAfterHeader
                        ? Number.parseFloat(retryAfterHeader) * 1000
                        : BASE_DELAY_MS * 2 ** attempt;
                    const isServerError = response.status >= 500;
                    const errorMessage = isServerError
                        ? 'Discord API is currently down, try again later'
                        : response.status === 429
                            ? 'Discord API rate limit exceeded, try again later'
                            : `Discord API error: ${response.status} ${response.statusText}`;
                    lastError = new errors_1.KythiaArtsError(errorMessage);
                    if (attempt < MAX_RETRIES - 1) {
                        await sleep(delayMs);
                        continue;
                    }
                    throw lastError;
                }
                const isServerError = response.status >= 500;
                const errorMessage = isServerError
                    ? 'Discord API is currently down, try again later'
                    : response.status === 429
                        ? 'Discord API rate limit exceeded, try again later'
                        : `Discord API error: ${response.status} ${response.statusText}`;
                throw new errors_1.KythiaArtsError(errorMessage);
            }
            const contentType = response.headers.get('content-type');
            if (!contentType?.includes('application/json')) {
                throw new errors_1.KythiaArtsError(`Invalid response format. Expected JSON, but received: ${contentType}`);
            }
            const userData = (await response.json());
            if (!userData.created_at) {
                userData.created_at = new Date(Number(BigInt(userData.id) >> 22n) + 1420070400000).toISOString();
            }
            const avatarURL = getAvatarURL(userData.id, userData.avatar);
            const bannerURL = getBannerURL(userData.id, userData.banner);
            const result = {
                ...userData,
                assets: {
                    avatarURL,
                    defaultAvatarURL: `${DISCORD_CDN}/embed/avatars/${Number.parseInt(userData.id, 10) % 5}.png`,
                    bannerURL,
                    badges: (0, badges_1.getBadgesFromFlags)(userData.public_flags || 0),
                },
                decoration: {
                    avatarFrame: getAvatarDecorationURL(userData.avatar_decoration_data) ||
                        undefined,
                },
            };
            return result;
        }
        catch (error) {
            if (error instanceof node_fetch_1.FetchError) {
                lastError = new errors_1.KythiaArtsError('Discord API is currently down, try again later');
                if (attempt < MAX_RETRIES - 1) {
                    await sleep(BASE_DELAY_MS * 2 ** attempt);
                    continue;
                }
                throw lastError;
            }
            if (error instanceof errors_1.KythiaArtsError) {
                throw error;
            }
            throw new errors_1.KythiaArtsError(error?.message || 'Failed to fetch user data from Discord');
        }
    }
    throw (lastError ?? new errors_1.KythiaArtsError('Failed to fetch user data from Discord'));
}
exports.default = fetchUserData;
//# sourceMappingURL=discord-api.js.map