"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CoinMarketCapClient = void 0;
const AppError_js_1 = require("../../shared/errors/AppError.js");
class CoinMarketCapClient {
    apiKey;
    cacheTtlSeconds;
    cache;
    constructor(apiKey, cacheTtlSeconds) {
        this.apiKey = apiKey;
        this.cacheTtlSeconds = cacheTtlSeconds;
    }
    async getTopTrendingTokens(limit) {
        if (this.cache && this.cache.expiresAt > Date.now()) {
            return this.cache.tokens.slice(0, limit);
        }
        const tokens = await this.fetchTrendingTokens(limit).catch((error) => {
            if (error instanceof AppError_js_1.ExternalApiError && error.code === "CMC_TRENDING_FORBIDDEN") {
                return this.fetchListingTokens(limit);
            }
            throw error;
        });
        this.cache = {
            expiresAt: Date.now() + this.cacheTtlSeconds * 1000,
            tokens
        };
        return tokens.slice(0, limit);
    }
    async fetchTrendingTokens(limit) {
        const latest = await this.getJson(`https://pro-api.coinmarketcap.com/v1/cryptocurrency/trending/latest?limit=${limit}`, { treat403As: "CMC_TRENDING_FORBIDDEN" });
        const trending = latest.data ?? [];
        if (trending.length === 0) {
            throw new AppError_js_1.ExternalApiError("CoinMarketCap returned no trending tokens.", "CMC_EMPTY_TRENDING");
        }
        return this.enrichWithContractInfo(trending);
    }
    async fetchListingTokens(limit) {
        const latest = await this.getJson(`https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?limit=${limit}`);
        const listings = latest.data ?? [];
        if (listings.length === 0) {
            throw new AppError_js_1.ExternalApiError("CoinMarketCap returned no market listings.", "CMC_EMPTY_LISTINGS");
        }
        return this.enrichWithContractInfo(listings);
    }
    async enrichWithContractInfo(items) {
        const ids = items.map((token) => token.id).join(",");
        const info = await this.getJson(`https://pro-api.coinmarketcap.com/v2/cryptocurrency/info?id=${ids}`);
        return items.map((token) => {
            const details = info.data?.[String(token.id)];
            return {
                cmcId: token.id,
                name: token.name,
                symbol: token.symbol.toUpperCase(),
                priceUsd: token.quote?.USD?.price,
                logoUrl: details?.logo,
                contractAddresses: (details?.contract_address ?? []).map((entry) => ({
                    network: entry.platform?.name ?? "",
                    address: entry.contract_address
                }))
            };
        });
    }
    async getJson(url, options = {}) {
        const response = await fetch(url, {
            headers: {
                "X-CMC_PRO_API_KEY": this.apiKey,
                Accept: "application/json"
            }
        });
        if (!response.ok) {
            if (response.status === 403 && options.treat403As) {
                throw new AppError_js_1.ExternalApiError(`CoinMarketCap endpoint returned HTTP 403`, options.treat403As);
            }
            throw new AppError_js_1.ExternalApiError(`CoinMarketCap request failed with HTTP ${response.status}`, "CMC_REQUEST_FAILED");
        }
        return (await response.json());
    }
}
exports.CoinMarketCapClient = CoinMarketCapClient;
