"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GenerateFarmLiquiditySignal = void 0;
const ValerisNetwork_js_1 = require("../../domain/value-objects/ValerisNetwork.js");
const AppError_js_1 = require("../../shared/errors/AppError.js");
const random_js_1 = require("../../shared/utils/random.js");
const MAX_DAILY_RECORDS = 10;
const SMART_CANDIDATE_POOLS = 20;
class GenerateFarmLiquiditySignal {
    platformRepository;
    constructor(platformRepository) {
        this.platformRepository = platformRepository;
    }
    async execute(networkCode) {
        const pools = await this.platformRepository.listLiquidityPools();
        const targetNetwork = (0, ValerisNetwork_js_1.parseNetworkCode)(networkCode);
        let activePools = pools.filter((pool) => pool.isActive && pool.tvl > 0);
        if (targetNetwork) {
            activePools = activePools.filter((pool) => pool.networkName?.toLowerCase() === targetNetwork.toLowerCase());
        }
        if (activePools.length === 0) {
            const networkMsg = targetNetwork ? `on ${targetNetwork}` : "across all networks";
            throw new AppError_js_1.AppError(`No active liquidity pools are available ${networkMsg} for signal generation.`, "NO_LIQUIDITY_POOLS", true);
        }
        const scoredPools = activePools
            .map((pool) => ({ pool, score: this.scorePool(pool) }))
            .sort((a, b) => b.score - a.score)
            .slice(0, Math.min(SMART_CANDIDATE_POOLS, activePools.length))
            .map((item) => item.pool);
        // Randomly select MAX_DAILY_RECORDS from the smart candidate set so every
        // day has a fresh mix of high-quality pools, each with a clear reason.
        const selectedPools = (0, random_js_1.shuffle)(scoredPools).slice(0, Math.min(MAX_DAILY_RECORDS, scoredPools.length));
        return selectedPools.map((pool) => this.buildSignal(pool));
    }
    scorePool(pool) {
        // Composite score: TVL weighted highest, then APR, then volume.
        // Use log scaling to avoid whales dominating completely.
        const tvlScore = Math.log10(Math.max(pool.tvl, 1)) * 10;
        const aprScore = Math.max(pool.apr, 0) * 2;
        const volumeScore = Math.log10(Math.max(pool.volume24h, 1));
        const feeScore = pool.fee * 5;
        return tvlScore + aprScore + volumeScore + feeScore;
    }
    buildSignal(pool) {
        const symbol = `${pool.token0Symbol}/${pool.token1Symbol}`;
        const name = `${pool.token0Name}/${pool.token1Name}`;
        const riskLevel = this.assessRisk(pool);
        const capital = (0, random_js_1.randomInt)(500, 5000);
        const durationDays = this.suggestDuration(pool.apr);
        const expectedYield = Number(((pool.apr / 100) * capital * (durationDays / 365)).toFixed(2));
        return {
            tokenName: `${name} LP`,
            symbol,
            network: pool.networkName ?? "Unknown",
            contractAddress: pool.address,
            category: "Farm Liquidity",
            side: "FARM",
            strategyName: "Yield Farm",
            entryPrice: 1,
            targetPrice: Number((1 + pool.apr / 100 / (365 / durationDays)).toFixed(6)),
            riskLevel,
            suggestedAmountUsd: capital,
            executionWindow: `${durationDays} days`,
            reasoning: this.buildReasoning(pool, symbol, expectedYield, durationDays),
            confidenceScore: this.confidenceScore(pool),
            poolAddress: pool.address,
            apr: pool.apr,
            tvl: pool.tvl,
            volume24h: pool.volume24h,
            fee: pool.fee,
            impermanentLossRisk: riskLevel
        };
    }
    assessRisk(pool) {
        if (pool.isStablePool)
            return "Low";
        if (pool.apr > 100 || pool.tvl < 50_000)
            return "High";
        if (pool.apr > 40 || pool.tvl < 250_000)
            return "Medium";
        return "Low";
    }
    suggestDuration(apr) {
        // Higher APR opportunities are usually shorter-lived.
        if (apr > 100)
            return (0, random_js_1.randomInt)(1, 3);
        if (apr > 40)
            return (0, random_js_1.randomInt)(3, 7);
        if (apr > 15)
            return (0, random_js_1.randomInt)(7, 14);
        return (0, random_js_1.randomInt)(14, 30);
    }
    confidenceScore(pool) {
        let score = 5;
        if (pool.isStablePool)
            score += 2;
        if (pool.tvl > 1_000_000)
            score += 2;
        if (pool.volume24h > 100_000)
            score += 1;
        if (pool.apr > 0 && pool.apr < 200)
            score += 1;
        return Math.min(10, score);
    }
    buildReasoning(pool, symbol, expectedYield, durationDays) {
        const parts = [];
        parts.push(`${symbol} shows a healthy ${pool.apr.toFixed(2)}% APR`);
        if (pool.tvl > 0)
            parts.push(`with $${pool.tvl.toLocaleString()} in TVL`);
        if (pool.volume24h > 0)
            parts.push(`and $${pool.volume24h.toLocaleString()} 24h volume`);
        parts.push(`— suggesting strong fee generation.`);
        if (pool.isStablePool)
            parts.push(` Stable-pair farming reduces impermanent-loss exposure.`);
        parts.push(` A $${expectedYield.toFixed(2)} yield estimate over ~${durationDays} day(s) makes this an attractive farm right now.`);
        return parts.join("");
    }
}
exports.GenerateFarmLiquiditySignal = GenerateFarmLiquiditySignal;
