"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BalanceService = void 0;
const ethers_1 = require("ethers");
const tronweb_1 = require("tronweb");
const erc20Abi = ["function balanceOf(address owner) view returns (uint256)"];
const decimalsAbi = ["function decimals() view returns (uint8)"];
const trc20Abi = [
    {
        constant: true,
        inputs: [{ name: "who", type: "address" }],
        name: "balanceOf",
        outputs: [{ name: "", type: "uint256" }],
        type: "function"
    }
];
const trc20DecimalsAbi = [
    {
        constant: true,
        inputs: [],
        name: "decimals",
        outputs: [{ name: "", type: "uint8" }],
        type: "function"
    }
];
class BalanceService {
    config;
    logger;
    decimalsCache = new Map();
    constructor(config, logger) {
        this.config = config;
        this.logger = logger;
    }
    async getDecimals(network) {
        const cached = this.decimalsCache.get(network);
        if (cached !== undefined)
            return cached;
        const decimals = await this.loadDecimals(network);
        this.decimalsCache.set(network, decimals);
        return decimals;
    }
    async getUsdtBalance(network, walletAddress) {
        if (network === "tron") {
            return this.getTronBalance(walletAddress);
        }
        return this.getEvmBalance(network, walletAddress);
    }
    async loadDecimals(network) {
        if (network === "tron") {
            return this.loadTronDecimals();
        }
        return this.loadEvmDecimals(network);
    }
    async loadEvmDecimals(network) {
        const networkConfig = this.config.paymentNetworks[network];
        if (!networkConfig)
            throw new Error(`${network} payments are not configured.`);
        if (networkConfig.usdtDecimals !== undefined) {
            return networkConfig.usdtDecimals;
        }
        try {
            const provider = new ethers_1.ethers.JsonRpcProvider(networkConfig.rpcUrl);
            const contract = new ethers_1.ethers.Contract(networkConfig.usdtAddress, decimalsAbi, provider);
            const decimals = (await contract.decimals());
            return Number(decimals);
        }
        catch (error) {
            this.logger?.warn(`Could not auto-detect decimals for ${network} USDT; falling back to 6.`, { error: error instanceof Error ? error.message : String(error) });
            return 6;
        }
    }
    async loadTronDecimals() {
        const networkConfig = this.config.paymentNetworks.tron;
        if (!networkConfig)
            throw new Error("Tron payments are not configured.");
        if (networkConfig.usdtDecimals !== undefined) {
            return networkConfig.usdtDecimals;
        }
        try {
            const tronWeb = new tronweb_1.TronWeb({ fullHost: networkConfig.fullHost, headers: tronHeaders(networkConfig.apiKey) });
            const contract = await tronWeb.contract(trc20DecimalsAbi, networkConfig.usdtContract);
            const decimals = await contract.decimals().call();
            return Number(decimals.toString());
        }
        catch (error) {
            this.logger?.warn("Could not auto-detect decimals for Tron USDT; falling back to 6.", { error: error instanceof Error ? error.message : String(error) });
            return 6;
        }
    }
    async getEvmBalance(network, walletAddress) {
        const networkConfig = this.config.paymentNetworks[network];
        if (!networkConfig)
            throw new Error(`${network} payments are not configured.`);
        if (!ethers_1.ethers.isAddress(walletAddress))
            throw new Error(`Invalid ${network} wallet address.`);
        if (!ethers_1.ethers.isAddress(networkConfig.usdtAddress))
            throw new Error(`Invalid ${network} USDT contract address.`);
        const provider = new ethers_1.ethers.JsonRpcProvider(networkConfig.rpcUrl);
        const contract = new ethers_1.ethers.Contract(networkConfig.usdtAddress, erc20Abi, provider);
        const balance = (await contract.balanceOf(walletAddress));
        return balance.toString();
    }
    async getTronBalance(walletAddress) {
        const networkConfig = this.config.paymentNetworks.tron;
        if (!networkConfig)
            throw new Error("Tron payments are not configured.");
        const tronWeb = new tronweb_1.TronWeb({ fullHost: networkConfig.fullHost, headers: tronHeaders(networkConfig.apiKey) });
        if (!tronweb_1.TronWeb.isAddress(walletAddress))
            throw new Error("Invalid Tron wallet address.");
        if (!tronweb_1.TronWeb.isAddress(networkConfig.usdtContract))
            throw new Error("Invalid Tron USDT contract address.");
        const contract = await tronWeb.contract(trc20Abi, networkConfig.usdtContract);
        const balance = await contract.balanceOf(walletAddress).call();
        return BigInt(balance.toString()).toString();
    }
}
exports.BalanceService = BalanceService;
const tronHeaders = (apiKey) => {
    return apiKey ? { "TRON-PRO-API-KEY": apiKey } : undefined;
};
