"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
require("dotenv/config");
require("reflect-metadata");
const data_source_1 = require("../infrastructure/persistence/data-source");
const redis_client_1 = require("../infrastructure/cache/redis-client");
const repositories_factory_1 = require("../main/factories/repositories.factory");
const services_factory_1 = require("../main/factories/services.factory");
const network_1 = require("../domain/entities/network");
const token_1 = require("../domain/entities/token");
const env_1 = require("../main/config/env");
const networks_seed_data_1 = require("./networks.seed-data");
const LAN_HOST = '192.168.0.101';
const replaceLocalhost = (url) => url.replace(/localhost/g, LAN_HOST);
const isExternalUrl = (url) => {
    const lower = url.toLowerCase();
    return ((lower.startsWith('http://') || lower.startsWith('https://')) &&
        !lower.startsWith(env_1.env.PUBLIC_BASE_URL.toLowerCase()));
};
const getTrustWalletNetworkLogoUrl = (chainId) => {
    const chain = networks_seed_data_1.evmTrustWalletChainByChainId[chainId];
    if (!chain) {
        return null;
    }
    return `https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/${chain}/info/logo.png`;
};
const run = async () => {
    await (0, data_source_1.initializeDatabase)();
    const repositories = (0, repositories_factory_1.createRepositories)();
    const services = (0, services_factory_1.createServices)(redis_client_1.redisClient);
    const { logger, imageStorage, coinMarketCapClient, cacheService } = services;
    const networksBySymbol = new Map();
    const hasSharedSymbol = (network) => (networksBySymbol.get(network.code.toUpperCase())?.length ?? 0) > 1;
    logger.info('Starting thumbnail healing', { publicBaseUrl: env_1.env.PUBLIC_BASE_URL });
    const networks = await repositories.networkRepository.findAll();
    const tokens = await repositories.tokenRepository.findAll();
    for (const network of networks) {
        const symbol = network.code.toUpperCase();
        const list = networksBySymbol.get(symbol) ?? [];
        list.push(network);
        networksBySymbol.set(symbol, list);
    }
    let healed = 0;
    let failed = 0;
    let skipped = 0;
    const updateNetworkThumbnail = async (network, newUrl, reason) => {
        const updatedNetwork = new network_1.Network(network.id, network.name, network.code, network.addressType, newUrl, network.explorer, network.chainId, network.status, network.mcap, network.createdAt, new Date());
        await repositories.networkRepository.update(updatedNetwork);
        logger.info(reason, {
            id: network.id,
            name: network.name,
            oldUrl: network.thumbnail,
            newUrl,
        });
    };
    for (const network of networks) {
        if (network.thumbnail?.includes('localhost')) {
            const newUrl = replaceLocalhost(network.thumbnail);
            await updateNetworkThumbnail(network, newUrl, 'Healed localhost network thumbnail');
            healed++;
            continue;
        }
        const sharedSymbol = hasSharedSymbol(network);
        if (sharedSymbol) {
            // Networks that share a symbol (e.g. ETH L2s such as Base, Scroll) cannot be
            // resolved by symbol, otherwise every L2 inherits the L1 logo (Ethereum).
            // Always re-evaluate these networks so existing wrong logos are corrected.
            try {
                let correctUrl = await coinMarketCapClient.getNetworkLogoUrlByName(network.name);
                if (!correctUrl && network.chainId != null) {
                    correctUrl = getTrustWalletNetworkLogoUrl(network.chainId);
                }
                if (!correctUrl) {
                    logger.warn('No correct logo source found for shared-symbol network, clearing thumbnail', {
                        id: network.id,
                        name: network.name,
                        symbol: network.code,
                    });
                    if (network.thumbnail !== null) {
                        await updateNetworkThumbnail(network, null, 'Cleared wrong shared-symbol network thumbnail');
                        healed++;
                    }
                    else {
                        skipped++;
                    }
                    continue;
                }
                // Avoid a redundant download when the network already points to the resolved source.
                if (network.thumbnail === correctUrl) {
                    skipped++;
                    continue;
                }
                // Do not pass metadata; the resolver's symbol fallback would reassign the L1 logo.
                const rawLocalUrl = await imageStorage.downloadAndStore('network', network.id, correctUrl);
                if (!rawLocalUrl) {
                    logger.warn('Failed to download correct network logo', {
                        id: network.id,
                        name: network.name,
                        url: correctUrl,
                    });
                    skipped++;
                    continue;
                }
                const localUrl = replaceLocalhost(rawLocalUrl);
                await updateNetworkThumbnail(network, localUrl, 'Healed network thumbnail (shared symbol)');
                healed++;
            }
            catch (error) {
                logger.error('Failed to heal shared-symbol network thumbnail', {
                    id: network.id,
                    name: network.name,
                    symbol: network.code,
                    url: network.thumbnail,
                    error,
                });
                failed++;
            }
            continue;
        }
        // Non-shared-symbol networks: only process external thumbnails.
        if (!network.thumbnail || !isExternalUrl(network.thumbnail)) {
            skipped++;
            continue;
        }
        try {
            const rawLocalUrl = await imageStorage.downloadAndStore('network', network.id, network.thumbnail, {
                name: network.name,
                symbol: network.code,
            });
            if (!rawLocalUrl) {
                logger.warn('No fallback logo found for network thumbnail, leaving original URL', {
                    id: network.id,
                    name: network.name,
                    url: network.thumbnail,
                });
                skipped++;
                continue;
            }
            const localUrl = replaceLocalhost(rawLocalUrl);
            await updateNetworkThumbnail(network, localUrl, 'Healed network thumbnail');
            healed++;
        }
        catch (error) {
            logger.error('Failed to heal network thumbnail', {
                id: network.id,
                name: network.name,
                url: network.thumbnail,
                error,
            });
            failed++;
        }
    }
    for (const token of tokens) {
        if (token.thumbnail?.includes('localhost')) {
            const newUrl = replaceLocalhost(token.thumbnail);
            const updatedToken = new token_1.Token(token.id, token.isNative, token.address, token.networkId, newUrl, token.name, token.symbol, token.decimals, token.code, token.info, token.isActive, token.minimumSwapValue, token.mcap, token.createdAt, new Date());
            await repositories.tokenRepository.update(updatedToken);
            logger.info('Healed localhost token thumbnail', {
                id: token.id,
                name: token.name,
                oldUrl: token.thumbnail,
                newUrl,
            });
            healed++;
            continue;
        }
        if (!token.thumbnail || !isExternalUrl(token.thumbnail)) {
            skipped++;
            continue;
        }
        try {
            const rawLocalUrl = await imageStorage.downloadAndStore('token', token.id, token.thumbnail, {
                name: token.name,
                symbol: token.symbol,
            });
            if (!rawLocalUrl) {
                logger.warn('No fallback logo found for token thumbnail, leaving original URL', {
                    id: token.id,
                    name: token.name,
                    url: token.thumbnail,
                });
                skipped++;
                continue;
            }
            const localUrl = replaceLocalhost(rawLocalUrl);
            const updatedToken = new token_1.Token(token.id, token.isNative, token.address, token.networkId, localUrl, token.name, token.symbol, token.decimals, token.code, token.info, token.isActive, token.minimumSwapValue, token.mcap, token.createdAt, new Date());
            await repositories.tokenRepository.update(updatedToken);
            logger.info('Healed token thumbnail', {
                id: token.id,
                name: token.name,
                oldUrl: token.thumbnail,
                newUrl: localUrl,
            });
            healed++;
        }
        catch (error) {
            logger.error('Failed to heal token thumbnail', {
                id: token.id,
                name: token.name,
                url: token.thumbnail,
                error,
            });
            failed++;
        }
    }
    logger.info('Thumbnail healing complete', {
        networks: networks.length,
        tokens: tokens.length,
        healed,
        failed,
        skipped,
    });
    // Invalidate the cached networks list so the app fetches updated thumbnails.
    await cacheService.delete('networks:list');
    logger.info('Invalidated networks list cache');
    await redis_client_1.redisClient.quit();
    process.exit(failed > 0 ? 1 : 0);
};
run().catch((error) => {
    // eslint-disable-next-line no-console
    console.error('Thumbnail healing failed', error);
    process.exit(1);
});
//# sourceMappingURL=heal-thumbnails.js.map