@page "/Trackers"
@using System.Collections.Concurrent
@using System.Timers
@using Aster.Net.Interfaces
@using Binance.Net.Interfaces
@using BingX.Net.Interfaces
@using Bitfinex.Net.Interfaces
@using Bitget.Net.Interfaces;
@using BitMEX.Net.Interfaces;
@using BitMart.Net.Interfaces;
@using BloFin.Net.Interfaces
@using Bybit.Net.Interfaces
@using CoinEx.Net.Interfaces
@using CoinW.Net.Interfaces
@using Coinbase.Net.Interfaces
@using CryptoExchange.Net.Interfaces
@using CryptoCom.Net.Interfaces
@using CryptoExchange.Net.SharedApis
@using CryptoExchange.Net.Trackers.Trades
@using DeepCoin.Net.Interfaces
@using GateIo.Net.Interfaces
@using HTX.Net.Interfaces
@using HyperLiquid.Net.Interfaces
@using Kraken.Net.Interfaces
@using Kucoin.Net.Clients
@using Kucoin.Net.Interfaces
@using Mexc.Net.Interfaces
@using OKX.Net.Interfaces;
@using Upbit.Net.Interfaces;
@using Toobit.Net.Interfaces;
@using WhiteBit.Net.Interfaces
@using XT.Net.Interfaces
@inject IAsterTrackerFactory asterFactory
@inject IBinanceTrackerFactory binanceFactory
@inject IBingXTrackerFactory bingXFactory
@inject IBitfinexTrackerFactory bitfinexFactory
@inject IBitgetTrackerFactory bitgetFactory
@inject IBitMartTrackerFactory bitmartFactory
@inject IBitMEXTrackerFactory bitmexFactory
@inject IBloFinTrackerFactory bloFinFactory
@inject IBybitTrackerFactory bybitFactory
@inject ICoinbaseTrackerFactory coinbaseFactory
@inject ICoinExTrackerFactory coinExFactory
@inject ICoinWTrackerFactory coinWFactory
@inject ICryptoComTrackerFactory cryptocomFactory
@inject IDeepCoinTrackerFactory deepCoinFactory
@inject IGateIoTrackerFactory gateioFactory
@inject IHTXTrackerFactory htxFactory
@inject IHyperLiquidTrackerFactory hyperLiquidFactory
@inject IKrakenTrackerFactory krakenFactory
@inject IKucoinTrackerFactory kucoinFactory
@inject IMexcTrackerFactory mexcFactory
@inject IOKXTrackerFactory okxFactory
@inject IToobitTrackerFactory toobitFactory
@inject IUpbitTrackerFactory upbitFactory
@inject IWhiteBitTrackerFactory whitebitFactory
@inject IXTTrackerFactory xtFactory
@implements IDisposable

<h3>Trade Trackers, live updates:</h3>
<div style="display:flex; flex-wrap: wrap;">
    @foreach (var tracker in _trackers.OrderBy(p => p.Exchange))
    {
        <div style="margin-bottom: 20px; flex: 1; min-width: 700px;">
            <h4>@tracker.Exchange</h4>
            @foreach(var line in GetInfo(tracker))
            {
                <div>@line</div>
            }
        </div>
    }
</div>

@code{
    private List<ITradeTracker> _trackers = new List<ITradeTracker>();
    private Timer _timer;

    protected override async Task OnInitializedAsync()
    {
        var symbol = new SharedSymbol(TradingMode.Spot, "BTC", SharedSymbol.UsdOrStable);
        var futuresSymbol = new SharedSymbol(TradingMode.PerpetualLinear, "BTC", SharedSymbol.UsdOrStable);

        _trackers = new List<ITradeTracker>
            {
                { asterFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
                { binanceFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
                { bingXFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
                { bitfinexFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
                { bitgetFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
                { bitmartFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
                { bitmexFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
                { bloFinFactory.CreateTradeTracker(futuresSymbol, period: TimeSpan.FromMinutes(5)) },
                { bybitFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
                { coinbaseFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
                { coinExFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
                { coinWFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
                { cryptocomFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
                { deepCoinFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
                { gateioFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
                { htxFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
                { hyperLiquidFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
                { krakenFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
                { kucoinFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
                { mexcFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
                { okxFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
                { toobitFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
                { upbitFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
                { whitebitFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
                { xtFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
            };

        await Task.WhenAll(_trackers.Select(b => b.StartAsync(false)));

        // Use a manual update timer so the page isn't refreshed too often
        _timer = new Timer(500);
        _timer.Start();
        _timer.Elapsed += (o, e) => InvokeAsync(StateHasChanged);
    }

    private string[] GetInfo(ITradeTracker tracker)
    {
        var secondLastMinute = tracker.GetStats(DateTime.UtcNow.AddMinutes(-2), DateTime.UtcNow.AddMinutes(-1));
        var lastMinute = tracker.GetStats(DateTime.UtcNow.AddMinutes(-1));
        var compare = lastMinute.CompareTo(secondLastMinute);

        return [
            $"{tracker.SymbolName} | {tracker.Status} - Synced from {tracker.SyncedFrom}",
            $"Total trades: {tracker.Count}",
            $"Trades last minute: {lastMinute.TradeCount}, minute before: {secondLastMinute.TradeCount}",
            $"Average weighted price: {lastMinute.VolumeWeightedAveragePrice}, minute before: {secondLastMinute.VolumeWeightedAveragePrice}, dif: {compare.VolumeWeightedAveragePriceDif.PercentageDifference}%"
        ];
    }

    public void Dispose()
    {
        _timer?.Stop();
        _timer?.Dispose();
        foreach (var tracker in _trackers.Where(b => b.Status != CryptoExchange.Net.Objects.SyncStatus.Disconnected))
            // It's not necessary to wait for this
            _ = tracker.StopAsync();
    }
}