"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GenerateValerisArbitrageSignal = void 0;
const AppError_js_1 = require("../../shared/errors/AppError.js");
const random_js_1 = require("../../shared/utils/random.js");
const time_js_1 = require("../../shared/utils/time.js");
const ValerisNetwork_js_1 = require("../../domain/value-objects/ValerisNetwork.js");
const MarketDataUtils_js_1 = require("./shared/MarketDataUtils.js");
class GenerateValerisArbitrageSignal {
    marketDataRepository;
    platformRepository;
    getAdminJwt;
    cleanupWorker;
    logger;
    constructor(marketDataRepository, platformRepository, getAdminJwt, cleanupWorker, logger) {
        this.marketDataRepository = marketDataRepository;
        this.platformRepository = platformRepository;
        this.getAdminJwt = getAdminJwt;
        this.cleanupWorker = cleanupWorker;
        this.logger = logger;
    }
    async execute(networkCode) {
        const tokens = await (0, MarketDataUtils_js_1.filterValerisTrendingTokens)((limit) => this.marketDataRepository.getTopTrendingTokens(limit), 20, networkCode);
        if (tokens.length === 0) {
            const networkMsg = networkCode ? `for the selected network` : `on Lychee-supported networks`;
            throw new AppError_js_1.AppError(`No trending tokens ${networkMsg} are available for arbitrage right now.`, "NO_ARBITRAGE_TOKENS", true);
        }
        const token = (0, random_js_1.chooseOne)(tokens);
        const actualMarketPrice = token.priceUsd ?? 0;
        if (!actualMarketPrice) {
            throw new AppError_js_1.AppError("Market price is unavailable for the selected token.", "PRICE_UNAVAILABLE", true);
        }
        // Ensure the token exists on the platform; import if missing.
        this.logger?.info("Ensuring Lychee arbitrage token exists on platform.", { symbol: token.symbol, network: token.valerisNetwork });
        const platformToken = await this.ensurePlatformToken(token);
        if (platformToken) {
            this.logger?.info("Lychee arbitrage platform token ready.", { tokenId: platformToken.id, symbol: platformToken.symbol });
        }
        else {
            this.logger?.warn("Could not ensure Lychee arbitrage token on platform; signal will be read-only.", { symbol: token.symbol });
        }
        // Spread can be positive or negative between 15% and 25%.
        const spread = (0, random_js_1.chooseOne)([1, -1]) * (0, random_js_1.randomFloat)(15, 25, 2);
        const platformPrice = Number((actualMarketPrice * (1 + spread / 100)).toFixed(8));
        const side = spread > 0 ? "BUY" : "SELL";
        const capital = (0, random_js_1.randomInt)(969, 9696);
        const windowMinutes = (0, random_js_1.randomInt)(1, 6);
        const executionWindow = `${windowMinutes} minutes`;
        if (platformToken) {
            const jwt = await this.getAdminJwt.execute();
            try {
                this.logger?.info("Setting trailing custom price for Lychee arbitrage.", { tokenId: platformToken.id, symbol: platformToken.symbol, spread });
                await this.platformRepository.setCustomPrice(platformToken.id, platformPrice, "trailing", jwt, spread, `Lychee arbitrage spread ${spread.toFixed(2)}%`);
                this.logger?.info("Trailing custom price set for Lychee arbitrage.", { tokenId: platformToken.id, symbol: platformToken.symbol });
            }
            catch (error) {
                this.logger?.error("Failed to set trailing custom price for Lychee arbitrage.", {
                    tokenId: platformToken.id,
                    symbol: platformToken.symbol,
                    error: error instanceof Error ? error.message : String(error)
                });
                if (this.isUnauthorized(error)) {
                    try {
                        this.logger?.info("Refreshing admin JWT and retrying Lychee arbitrage custom price.", { tokenId: platformToken.id, symbol: platformToken.symbol });
                        const refreshedJwt = await this.getAdminJwt.execute(true);
                        await this.platformRepository.setCustomPrice(platformToken.id, platformPrice, "trailing", refreshedJwt, spread, `Lychee arbitrage spread ${spread.toFixed(2)}%`);
                        this.logger?.info("Trailing custom price set for Lychee arbitrage after JWT refresh.", { tokenId: platformToken.id, symbol: platformToken.symbol });
                    }
                    catch (retryError) {
                        this.logger?.error("Failed to set trailing custom price for Lychee arbitrage after JWT refresh.", {
                            tokenId: platformToken.id,
                            symbol: platformToken.symbol,
                            error: retryError instanceof Error ? retryError.message : String(retryError)
                        });
                        // Continue returning the signal; a missing custom price is logged, not fatal.
                    }
                }
                // Continue returning the signal even when custom-price setting fails.
            }
            await this.cleanupWorker.schedule({
                tokenId: platformToken.id,
                networkId: platformToken.networkId ?? "",
                tokenSymbol: platformToken.symbol || token.symbol,
                priceGap: spread,
                reason: `Lychee arbitrage signal window expired (${executionWindow})`,
                expiresAt: (0, time_js_1.minutesFromNow)(windowMinutes)
            });
        }
        return {
            tokenName: token.name,
            symbol: token.symbol,
            network: token.valerisNetwork,
            contractAddress: token.contractAddress,
            category: "Arbitrage Opportunities",
            side,
            strategyName: "Arbitrage Hawk",
            actualMarketPrice,
            platformPrice,
            entryPrice: actualMarketPrice,
            targetPrice: platformPrice,
            spreadPercentage: spread,
            estimatedProfitPercentage: Math.abs(spread),
            riskLevel: "High",
            suggestedAmountUsd: capital,
            executionWindow,
            reasoning: this.buildReasoning(token, side, actualMarketPrice, platformPrice, spread, windowMinutes),
            confidenceScore: Math.min(10, Math.max(5, 10 - Math.abs(spread) / 5))
        };
    }
    async ensurePlatformToken(token) {
        const networks = await this.platformRepository.listNetworks();
        const network = networks.find((n) => n.name.toLowerCase() === token.valerisNetwork.toLowerCase());
        if (!network)
            return undefined;
        const platformTokens = await this.platformRepository.listTokens();
        const existing = platformTokens.find((t) => {
            const contractMatches = token.contractAddress && t.contractAddress &&
                t.contractAddress.toLowerCase() === token.contractAddress.toLowerCase();
            const symbolNetworkMatches = t.symbol.toUpperCase() === token.symbol.toUpperCase() &&
                (t.networkId === network.id || (t.networkName?.toLowerCase() === token.valerisNetwork.toLowerCase()));
            return contractMatches || symbolNetworkMatches;
        });
        if (existing) {
            return { id: existing.id, networkId: existing.networkId ?? network.id, symbol: existing.symbol };
        }
        const contract = token.contractAddress
            ? { address: token.contractAddress, network: token.valerisNetwork }
            : (0, ValerisNetwork_js_1.pickNetworkContract)(token, token.valerisNetwork);
        if (!contract)
            return undefined;
        try {
            const jwt = await this.getAdminJwt.execute();
            const imported = await this.platformRepository.importToken(network.id, contract.address, jwt, token.logoUrl);
            return { id: imported.id, networkId: imported.networkId ?? network.id, symbol: imported.symbol };
        }
        catch {
            return undefined;
        }
    }
    buildReasoning(token, side, marketPrice, platformPrice, spread, windowMinutes) {
        const action = side === "BUY"
            ? `Buy ${token.symbol} on an external exchange and sell on Lyche Finance`
            : `Buy ${token.symbol} on Lychee Financeand sell on an external platform such as Trust Wallet`;
        return [
            `${token.name} (${token.symbol}) on ${token.valerisNetwork} shows a ${Math.abs(spread).toFixed(2)}% price divergence.`,
            ` Market reference is $${marketPrice.toFixed(6)} while the Lychee execution price is $${platformPrice.toFixed(6)}.`,
            ` Suggested action: ${action}.`,
            ` The window to capture this spread is estimated at ~${windowMinutes} minutes before it closes.`
        ].join("");
    }
    isUnauthorized(error) {
        if (!(error instanceof AppError_js_1.ExternalApiError))
            return false;
        const cause = error.cause;
        return cause?.status === 401 || cause?.status === 403;
    }
}
exports.GenerateValerisArbitrageSignal = GenerateValerisArbitrageSignal;
