using Managing.Api.Models.Responses;
using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Services;
using Managing.Application.Hubs;
using Managing.Application.ManageBot.Commands;
using Managing.Domain.Bots;
using Managing.Domain.Candles;
using Managing.Domain.Shared.Helpers;
using Managing.Domain.Statistics;
using Managing.Domain.Trades;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using static Managing.Common.Enums;

namespace Managing.Api.Controllers;

/// <summary>
/// Controller for handling data-related operations such as retrieving tickers, spotlight data, and candles.
/// Requires authorization for access.
/// </summary>
[ApiController]
[Route("[controller]")]
public class DataController : ControllerBase
{
    private readonly IExchangeService _exchangeService;
    private readonly IAccountService _accountService;
    private readonly ICacheService _cacheService;
    private readonly IStatisticService _statisticService;
    private readonly IHubContext<CandleHub> _hubContext;
    private readonly IMediator _mediator;

    /// <summary>
    /// Initializes a new instance of the <see cref="DataController"/> class.
    /// </summary>
    /// <param name="exchangeService">Service for interacting with exchanges.</param>
    /// <param name="accountService">Service for account management.</param>
    /// <param name="cacheService">Service for caching data.</param>
    /// <param name="statisticService">Service for statistical analysis.</param>
    /// <param name="hubContext">SignalR hub context for real-time communication.</param>
    /// <param name="mediator">Mediator for handling commands and queries.</param>
    public DataController(
        IExchangeService exchangeService,
        IAccountService accountService,
        ICacheService cacheService,
        IStatisticService statisticService,
        IHubContext<CandleHub> hubContext,
        IMediator mediator)
    {
        _exchangeService = exchangeService;
        _accountService = accountService;
        _cacheService = cacheService;
        _statisticService = statisticService;
        _hubContext = hubContext;
        _mediator = mediator;
    }

    /// <summary>
    /// Retrieves tickers for a given account and timeframe, utilizing caching to improve performance.
    /// </summary>
    /// <param name="timeframe">The timeframe for which to retrieve tickers.</param>
    /// <returns>An array of tickers.</returns>
    [HttpPost("GetTickers")]
    public async Task<ActionResult<List<TickerInfos>>> GetTickers(Timeframe timeframe)
    {
        var cacheKey = string.Concat(timeframe.ToString());
        var tickers = _cacheService.GetValue<List<TickerInfos>>(cacheKey);

        if (tickers == null || tickers.Count == 0)
        {
            var availableTicker = await _exchangeService.GetTickers(timeframe);

            tickers = MapTickerToTickerInfos(availableTicker);

            _cacheService.SaveValue(cacheKey, tickers, TimeSpan.FromHours(2));
        }

        return Ok(tickers);
    }

    private List<TickerInfos> MapTickerToTickerInfos(List<Ticker> availableTicker)
    {
        var tickerInfos = new List<TickerInfos>();
        var tokens = new Dictionary<string, string>
        {
            { "AAVE", "https://assets.coingecko.com/coins/images/12645/standard/AAVE.png?1696512452" },
            { "ADA", "https://assets.coingecko.com/coins/images/975/standard/cardano.png?1696502090" },
            { "APE", "https://assets.coingecko.com/coins/images/24383/standard/apecoin.jpg?1696523566" },
            {
                "ARB", "https://assets.coingecko.com/coins/images/16547/small/photo_2023-03-29_21.47.00.jpeg?1680097630"
            },
            { "ATOM", "https://assets.coingecko.com/coins/images/1481/standard/cosmos_hub.png?1696502525" },
            { "AVAX", "https://assets.coingecko.com/coins/images/12559/small/coin-round-red.png?1604021818" },
            { "BNB", "https://assets.coingecko.com/coins/images/825/standard/bnb-icon2_2x.png?1696501970" },
            { "BTC", "https://assets.coingecko.com/coins/images/1/small/bitcoin.png?1547033579" },
            { "DOGE", "https://assets.coingecko.com/coins/images/5/small/dogecoin.png?1547792256" },
            {
                "DOT",
                "https://static.coingecko.com/s/polkadot-73b0c058cae10a2f076a82dcade5cbe38601fad05d5e6211188f09eb96fa4617.gif"
            },
            { "ETH", "https://assets.coingecko.com/coins/images/279/small/ethereum.png?1595348880" },
            { "FIL", "https://assets.coingecko.com/coins/images/12817/standard/filecoin.png?1696512609" },
            { "GMX", "https://assets.coingecko.com/coins/images/18323/small/arbit.png?1631532468" },
            { "LINK", "https://assets.coingecko.com/coins/images/877/thumb/chainlink-new-logo.png?1547034700" },
            { "LTC", "https://assets.coingecko.com/coins/images/2/small/litecoin.png?1547033580" },
            { "MATIC", "https://assets.coingecko.com/coins/images/32440/standard/polygon.png?1698233684" },
            { "NEAR", "https://assets.coingecko.com/coins/images/10365/standard/near.jpg?1696510367" },
            { "OP", "https://assets.coingecko.com/coins/images/25244/standard/Optimism.png?1696524385" },
            { "PEPE", "https://assets.coingecko.com/coins/images/29850/standard/pepe-token.jpeg?1696528776" },
            { "SOL", "https://assets.coingecko.com/coins/images/4128/small/solana.png?1640133422" },
            { "UNI", "https://assets.coingecko.com/coins/images/12504/thumb/uniswap-uni.png?1600306604" },
            { "USDC", "https://assets.coingecko.com/coins/images/6319/thumb/USD_Coin_icon.png?1547042389" },
            { "USDT", "https://assets.coingecko.com/coins/images/325/thumb/Tether-logo.png?1598003707" },
            { "WIF", "https://assets.coingecko.com/coins/images/33566/standard/dogwifhat.jpg?1702499428" },
            { "XRP", "https://assets.coingecko.com/coins/images/44/small/xrp-symbol-white-128.png?1605778731" },
            { "SHIB", "https://assets.coingecko.com/coins/images/11939/standard/shiba.png?1696511800" },
            { "STX", "https://assets.coingecko.com/coins/images/2069/standard/Stacks_Logo_png.png?1709979332" },
            { "ORDI", "https://assets.coingecko.com/coins/images/30162/standard/ordi.png?1696529082" },
            { "APT", "https://assets.coingecko.com/coins/images/26455/standard/aptos_round.png?1696525528" },
            { "BOME", "https://assets.coingecko.com/coins/images/36071/standard/bome.png?1710407255" },
            { "MEME", "https://assets.coingecko.com/coins/images/32528/standard/memecoin_%282%29.png?1698912168" },
            { "FLOKI", "https://assets.coingecko.com/coins/images/16746/standard/PNG_image.png?1696516318" },
            { "MEW", "https://assets.coingecko.com/coins/images/36440/standard/MEW.png?1711442286" },
            { "TAO", "https://assets.coingecko.com/coins/images/28452/standard/ARUsPeNQ_400x400.jpeg?1696527447" },
            { "BONK", "https://assets.coingecko.com/coins/images/28600/standard/bonk.jpg?1696527587" },
            { "WLD", "https://assets.coingecko.com/coins/images/31069/standard/worldcoin.jpeg?1696529903" },
            {
                "tBTC",
                "https://assets.coingecko.com/coins/images/11224/standard/0x18084fba666a33d37592fa2633fd49a74dd93a88.png?1696511155"
            },
            { "EIGEN", "https://assets.coingecko.com/coins/images/37441/standard/eigen.jpg?1728023974" },
            { "SUI", "https://assets.coingecko.com/coins/images/26375/standard/sui-ocean-square.png?1727791290" },
            { "SEI", "https://assets.coingecko.com/coins/images/28205/standard/Sei_Logo_-_Transparent.png?1696527207" },
            { "DAI", "https://assets.coingecko.com/coins/images/9956/thumb/4943.png?1636636734" },
            { "TIA", "https://assets.coingecko.com/coins/images/31967/standard/tia.jpg?1696530772" },
            { "TRX", "https://assets.coingecko.com/coins/images/1094/standard/tron-logo.png?1696502193" },
            {
                "TON",
                "https://assets.coingecko.com/coins/images/17980/standard/photo_2024-09-10_17.09.00.jpeg?1725963446"
            },
            {
                "PENDLE",
                "https://assets.coingecko.com/coins/images/15069/standard/Pendle_Logo_Normal-03.png?1696514728"
            },
            { "wstETH", "https://assets.coingecko.com/coins/images/18834/standard/wstETH.png?1696518295" },
            { "USDe", "https://assets.coingecko.com/coins/images/33613/standard/USDE.png?1716355685" },
            { "SATS", "https://assets.coingecko.com/coins/images/30666/standard/_dD8qr3M_400x400.png?1702913020" },
            { "POL", "https://assets.coingecko.com/coins/images/32440/standard/polygon.png?1698233684" },
            { "XLM", "https://assets.coingecko.com/coins/images/100/standard/Stellar_symbol_black_RGB.png?1696501482" },
            { "BCH", "https://assets.coingecko.com/coins/images/780/standard/bitcoin-cash-circle.png?1696501932" },
            { "ICP", "https://assets.coingecko.com/coins/images/14495/standard/Internet_Computer_logo.png?1696514180" },
            { "RENDER", "https://assets.coingecko.com/coins/images/11636/standard/rndr.png?1696511529" },
            { "INJ", "https://assets.coingecko.com/coins/images/12882/standard/Secondary_Symbol.png?1696512670" },
            { "TRUMP", "https://assets.coingecko.com/coins/images/53746/standard/trump.png?1737171561" },
            { "MELANIA", "https://assets.coingecko.com/coins/images/53775/standard/melania-meme.png?1737329885" },
            { "ENA", "https://assets.coingecko.com/coins/images/36530/standard/ethena.png?1711701436" },
            { "FARTCOIN", "https://assets.coingecko.com/coins/images/50891/standard/fart.jpg?1729503972" },
            { "AI16Z", "https://assets.coingecko.com/coins/images/51090/standard/AI16Z.jpg?1730027175" },
            { "ANIME", "https://assets.coingecko.com/coins/images/53575/standard/anime.jpg?1736748703" },
            { "BERA", "https://assets.coingecko.com/coins/images/25235/standard/BERA.png?1738822008" },
            { "VIRTUAL", "https://assets.coingecko.com/coins/images/34057/standard/LOGOMARK.png?1708356054" },
            {
                "PENGU",
                "https://assets.coingecko.com/coins/images/52622/standard/PUDGY_PENGUINS_PENGU_PFP.png?1733809110"
            },
            { "FET", "https://assets.coingecko.com/coins/images/5681/standard/ASI.png?1719827289" },
            { "ONDO", "https://assets.coingecko.com/coins/images/26580/standard/ONDO.png?1696525656" },
            { "AIXBT", "https://assets.coingecko.com/coins/images/51784/standard/3.png?1731981138" },
            {
                "CAKE",
                "https://assets.coingecko.com/coins/images/12632/standard/pancakeswap-cake-logo_%281%29.png?1696512440"
            },
            { "S", "https://assets.coingecko.com/coins/images/38108/standard/200x200_Sonic_Logo.png?1734679256" },
            { "JUP", "https://assets.coingecko.com/coins/images/34188/standard/jup.png?1704266489" },
            { "HYPE", "https://assets.coingecko.com/coins/images/50882/standard/hyperliquid.jpg?1729431300" },
            { "OM", "https://assets.coingecko.com/coins/images/12151/standard/OM_Token.png?1696511991" }
        };

        foreach (var ticker in availableTicker)
        {
            var tickerInfo = new TickerInfos
            {
                Ticker = ticker,
                ImageUrl = tokens.GetValueOrDefault(ticker.ToString(),
                    "https://assets.coingecko.com/coins/images/1/small/bitcoin.png?1547033579") // Default to BTC image if not found
            };
            tickerInfos.Add(tickerInfo);
        }

        return tickerInfos;
    }

    /// <summary>
    /// Retrieves the latest spotlight overview, using caching to enhance response times.
    /// </summary>
    /// <returns>A <see cref="SpotlightOverview"/> object containing spotlight data.</returns>
    [Authorize]
    [HttpGet("Spotlight")]
    public ActionResult<SpotlightOverview> GetSpotlight()
    {
        var overview = _cacheService.GetOrSave(nameof(SpotlightOverview),
            () => { return _statisticService.GetLastSpotlight(DateTime.Now.AddDays(-2)); }, TimeSpan.FromMinutes(2));

        if (overview?.Spotlights.Count < overview?.ScenarioCount || overview == null)
        {
            overview = _statisticService.GetLastSpotlight(DateTime.Now.AddDays(-2));
        }

        return Ok(overview);
    }

    /// <summary>
    /// Retrieves candle data for a given exchange, ticker, start date, and timeframe.
    /// </summary>
    /// <param name="exchange">The exchange to retrieve candles from.</param>
    /// <param name="ticker">The ticker symbol to retrieve candles for.</param>
    /// <param name="startDate">The start date for the candle data.</param>
    /// <param name="timeframe">The timeframe for the candle data.</param>
    /// <returns>A list of <see cref="Candle"/> objects.</returns>
    [Authorize]
    [HttpGet("GetCandles")]
    public async Task<ActionResult<List<Candle>>> GetCandles(TradingExchanges exchange, Ticker ticker,
        DateTime startDate, Timeframe timeframe)
    {
        return Ok(await _exchangeService.GetCandlesInflux(exchange, ticker, startDate, timeframe));
    }

    /// <summary>
    /// Retrieves statistics about currently running bots and their change in the last 24 hours.
    /// </summary>
    /// <returns>A <see cref="StrategiesStatisticsViewModel"/> containing bot statistics.</returns>
    [HttpGet("GetStrategiesStatistics")]
    public async Task<ActionResult<StrategiesStatisticsViewModel>> GetStrategiesStatistics()
    {
        const string cacheKey = "StrategiesStatistics";
        const string previousCountKey = "PreviousBotsCount";

        // Check if the statistics are already cached
        var cachedStats = _cacheService.GetValue<StrategiesStatisticsViewModel>(cacheKey);

        if (cachedStats != null)
        {
            return Ok(cachedStats);
        }

        // Get active bots
        var activeBots = await _mediator.Send(new GetActiveBotsCommand());
        var currentCount = activeBots.Count;

        // Get previous count from cache
        var previousCount = _cacheService.GetValue<int>(previousCountKey);

        // Calculate change - if no previous value, set current count as the change (all are new)
        int change;
        if (previousCount == 0)
        {
            // First time running - assume all bots are new (positive change)
            change = currentCount;
        }
        else
        {
            // Calculate actual difference between current and previous count
            change = currentCount - previousCount;
        }

        // Create the response
        var botsStatistics = new StrategiesStatisticsViewModel
        {
            TotalStrategiesRunning = currentCount,
            ChangeInLast24Hours = change
        };

        // Store current count for future comparison (with 24 hour expiration)
        _cacheService.SaveValue(previousCountKey, currentCount, TimeSpan.FromHours(24));

        // Cache the statistics for 5 minutes
        _cacheService.SaveValue(cacheKey, botsStatistics, TimeSpan.FromMinutes(5));

        return Ok(botsStatistics);
    }

    /// <summary>
    /// Retrieves the top 3 performing strategies based on ROI.
    /// </summary>
    /// <returns>A <see cref="TopStrategiesViewModel"/> containing the top performing strategies.</returns>
    [HttpGet("GetTopStrategies")]
    public async Task<ActionResult<TopStrategiesViewModel>> GetTopStrategies()
    {
        const string cacheKey = "TopStrategies";

        // Check if the top strategies are already cached
        var cachedStrategies = _cacheService.GetValue<TopStrategiesViewModel>(cacheKey);

        if (cachedStrategies != null)
        {
            return Ok(cachedStrategies);
        }

        // Get active bots
        var activeBots = await _mediator.Send(new GetActiveBotsCommand());

        // Calculate PnL for each bot once and store in a list of tuples
        var botsWithPnL = activeBots
            .Select(bot => new { Bot = bot, PnL = bot.GetProfitAndLoss() })
            .OrderByDescending(item => item.PnL)
            .Take(3)
            .ToList();

        // Map to view model
        var topStrategies = new TopStrategiesViewModel
        {
            TopStrategies = botsWithPnL
                .Select(item => new StrategyPerformance
                {
                    StrategyName = item.Bot.Name,
                    PnL = item.PnL
                })
                .ToList()
        };

        // Cache the result for 10 minutes
        _cacheService.SaveValue(cacheKey, topStrategies, TimeSpan.FromMinutes(10));

        return Ok(topStrategies);
    }

    /// <summary>
    /// Retrieves list of the active strategies for a user with detailed information
    /// </summary>
    /// <param name="agentName">The agentName to retrieve strategies for</param>
    /// <returns>A list of detailed strategy information</returns>
    [HttpGet("GetUserStrategies")]
    public async Task<ActionResult<List<UserStrategyDetailsViewModel>>> GetUserStrategies(string agentName)
    {
        string cacheKey = $"UserStrategies_{agentName}";

        // Check if the user strategy details are already cached
        var cachedDetails = _cacheService.GetValue<List<UserStrategyDetailsViewModel>>(cacheKey);

        if (cachedDetails != null && cachedDetails.Count > 0)
        {
            return Ok(cachedDetails);
        }

        // Get all strategies for the specified user
        var userStrategies = await _mediator.Send(new GetUserStrategiesCommand(agentName));

        // Convert to detailed view model with additional information
        var result = userStrategies.Select(strategy => MapStrategyToViewModel(strategy)).ToList();

        // Cache the results for 5 minutes
        _cacheService.SaveValue(cacheKey, result, TimeSpan.FromMinutes(5));

        return Ok(result);
    }

    /// <summary>
    /// Retrieves a specific strategy for a user by strategy name
    /// </summary>
    /// <param name="agentName">The agent/user name to retrieve the strategy for</param>
    /// <param name="strategyName">The name of the strategy to retrieve</param>
    /// <returns>Detailed information about the requested strategy</returns>
    [HttpGet("GetUserStrategy")]
    public async Task<ActionResult<UserStrategyDetailsViewModel>> GetUserStrategy(string agentName, string strategyName)
    {
        string cacheKey = $"UserStrategy_{agentName}_{strategyName}";

        // Check if the user strategy details are already cached
        var cachedDetails = _cacheService.GetValue<UserStrategyDetailsViewModel>(cacheKey);

        if (cachedDetails != null)
        {
            return Ok(cachedDetails);
        }

        // Get the specific strategy for the user
        var strategy = await _mediator.Send(new GetUserStrategyCommand(agentName, strategyName));

        if (strategy == null)
        {
            return NotFound($"Strategy '{strategyName}' not found for user '{agentName}'");
        }

        // Map the strategy to a view model using the shared method
        var result = MapStrategyToViewModel(strategy);

        // Cache the results for 5 minutes
        _cacheService.SaveValue(cacheKey, result, TimeSpan.FromMinutes(5));

        return Ok(result);
    }

    /// <summary>
    /// Maps a trading bot to a strategy view model with detailed statistics
    /// </summary>
    /// <param name="strategy">The trading bot to map</param>
    /// <returns>A view model with detailed strategy information</returns>
    private UserStrategyDetailsViewModel MapStrategyToViewModel(ITradingBot strategy)
    {
        // Get the runtime directly from the bot
        TimeSpan runtimeSpan = strategy.GetRuntime();

        // Get the startup time from the bot's internal property
        // If bot is not running, we use MinValue as a placeholder
        DateTime startupTime = DateTime.MinValue;
        if (strategy is Bot bot && bot.StartupTime != DateTime.MinValue)
        {
            startupTime = bot.StartupTime;
        }

        // Calculate ROI percentage based on PnL relative to account value
        decimal pnl = strategy.GetProfitAndLoss();

        // If we had initial investment amount, we could calculate ROI like:
        decimal initialInvestment = 1000; // Example placeholder, ideally should come from the account
        decimal roi = pnl != 0 ? (pnl / initialInvestment) * 100 : 0;

        // Calculate volume statistics
        decimal totalVolume = TradingBox.GetTotalVolumeTraded(strategy.Positions);
        decimal volumeLast24h = TradingBox.GetLast24HVolumeTraded(strategy.Positions);

        // Calculate win/loss statistics
        (int wins, int losses) = TradingBox.GetWinLossCount(strategy.Positions);

        // Calculate ROI for last 24h
        decimal roiLast24h = TradingBox.GetLast24HROI(strategy.Positions);

        return new UserStrategyDetailsViewModel
        {
            Name = strategy.Name,
            ScenarioName = strategy.Config.ScenarioName,
            State = strategy.GetStatus() == BotStatus.Up.ToString() ? "RUNNING" :
                strategy.GetStatus() == BotStatus.Down.ToString() ? "STOPPED" : "UNUSED",
            PnL = pnl,
            ROIPercentage = roi,
            ROILast24H = roiLast24h,
            Runtime = startupTime,
            WinRate = strategy.GetWinRate(),
            TotalVolumeTraded = totalVolume,
            VolumeLast24H = volumeLast24h,
            Wins = wins,
            Losses = losses,
            Positions = strategy.Positions.OrderByDescending(p => p.Date)
                .ToList(), // Include sorted positions with most recent first
            Identifier = strategy.Identifier,
        };
    }

    /// <summary>
    /// Retrieves a summary of platform activity across all agents
    /// </summary>
    /// <param name="timeFilter">Time filter to apply (24H, 3D, 1W, 1M, 1Y, Total)</param>
    /// <returns>A summary of platform activity including per-agent statistics</returns>
    [HttpGet("GetPlatformSummary")]
    public async Task<ActionResult<PlatformSummaryViewModel>> GetPlatformSummary(string timeFilter = "Total")
    {
        // Validate time filter
        var validTimeFilters = new[] { "24H", "3D", "1W", "1M", "1Y", "Total" };
        if (!validTimeFilters.Contains(timeFilter))
        {
            timeFilter = "Total"; // Default to Total if invalid
        }

        string cacheKey = $"PlatformSummary_{timeFilter}";

        // Check if the platform summary is already cached
        var cachedSummary = _cacheService.GetValue<PlatformSummaryViewModel>(cacheKey);

        if (cachedSummary != null)
        {
            return Ok(cachedSummary);
        }

        // Get all agents and their strategies
        var agentsWithStrategies = await _mediator.Send(new GetAllAgentsCommand(timeFilter));

        // Create the platform summary
        var summary = new PlatformSummaryViewModel
        {
            TotalAgents = agentsWithStrategies.Count,
            TotalActiveStrategies = agentsWithStrategies.Values.Sum(list => list.Count),
            TimeFilter = timeFilter
        };

        // Calculate total platform metrics
        decimal totalPlatformPnL = 0;
        decimal totalPlatformVolume = 0;
        decimal totalPlatformVolumeLast24h = 0;

        // Create summaries for each agent
        foreach (var agent in agentsWithStrategies)
        {
            var user = agent.Key;
            var strategies = agent.Value;

            if (strategies.Count == 0)
            {
                continue; // Skip agents with no strategies
            }

            // Combine all positions from all strategies
            var allPositions = strategies.SelectMany<ITradingBot, Position>(s => s.Positions).ToList();

            // Calculate agent metrics
            decimal totalPnL = TradingBox.GetPnLInTimeRange(allPositions, timeFilter);
            decimal pnlLast24h = TradingBox.GetPnLInTimeRange(allPositions, "24H");

            decimal totalROI = TradingBox.GetROIInTimeRange(allPositions, timeFilter);
            decimal roiLast24h = TradingBox.GetROIInTimeRange(allPositions, "24H");

            (int wins, int losses) = TradingBox.GetWinLossCountInTimeRange(allPositions, timeFilter);

            // Calculate trading volumes
            decimal totalVolume = TradingBox.GetTotalVolumeTraded(allPositions);
            decimal volumeLast24h = TradingBox.GetLast24HVolumeTraded(allPositions);

            // Calculate win rate
            int averageWinRate = 0;
            if (wins + losses > 0)
            {
                averageWinRate = (wins * 100) / (wins + losses);
            }

            // Add to agent summaries
            var agentSummary = new AgentSummaryViewModel
            {
                AgentName = user.AgentName,
                TotalPnL = totalPnL,
                PnLLast24h = pnlLast24h,
                TotalROI = totalROI,
                ROILast24h = roiLast24h,
                Wins = wins,
                Losses = losses,
                AverageWinRate = averageWinRate,
                ActiveStrategiesCount = strategies.Count,
                TotalVolume = totalVolume,
                VolumeLast24h = volumeLast24h
            };

            summary.AgentSummaries.Add(agentSummary);

            // Add to platform totals
            totalPlatformPnL += totalPnL;
            totalPlatformVolume += totalVolume;
            totalPlatformVolumeLast24h += volumeLast24h;
        }

        // Set the platform totals
        summary.TotalPlatformPnL = totalPlatformPnL;
        summary.TotalPlatformVolume = totalPlatformVolume;
        summary.TotalPlatformVolumeLast24h = totalPlatformVolumeLast24h;

        // Sort agent summaries by total PnL (highest first)
        summary.AgentSummaries = summary.AgentSummaries.OrderByDescending(a => a.TotalPnL).ToList();

        // Cache the results for 5 minutes
        _cacheService.SaveValue(cacheKey, summary, TimeSpan.FromMinutes(5));

        return Ok(summary);
    }

    /// <summary>
    /// Retrieves balance history for a specific agent within a date range
    /// </summary>
    /// <param name="agentName">The name of the agent to retrieve balances for</param>
    /// <param name="startDate">The start date for the balance history</param>
    /// <param name="endDate">Optional end date for the balance history (defaults to current time)</param>
    /// <returns>A list of agent balances within the specified date range</returns>
    [HttpGet("GetAgentBalances")]
    public async Task<ActionResult<AgentBalanceHistory>> GetAgentBalances(
        string agentName,
        DateTime startDate,
        DateTime? endDate = null)
    {
        var balances = await _statisticService.GetAgentBalances(agentName, startDate, endDate);
        return Ok(balances);
    }

    /// <summary>
    /// Retrieves a paginated list of the best performing agents based on their total value
    /// </summary>
    /// <param name="startDate">The start date for calculating agent performance</param>
    /// <param name="endDate">Optional end date for calculating agent performance (defaults to current time)</param>
    /// <param name="page">Page number (defaults to 1)</param>
    /// <param name="pageSize">Number of items per page (defaults to 10)</param>
    /// <returns>A paginated list of agent balances and total count</returns>
    [HttpGet("GetBestAgents")]
    public async Task<ActionResult<BestAgentsResponse>> GetBestAgents(
        DateTime startDate,
        DateTime? endDate = null,
        int page = 1,
        int pageSize = 10)
    {
        var (agents, totalCount) = await _statisticService.GetBestAgents(startDate, endDate, page, pageSize);

        var response = new BestAgentsResponse
        {
            Agents = agents,
            TotalCount = totalCount,
            CurrentPage = page,
            PageSize = pageSize,
            TotalPages = (int)Math.Ceiling(totalCount / (double)pageSize)
        };

        return Ok(response);
    }
}