using System.Net.Http.Json;
using Managing.Application.Abstractions.Services;
using Managing.Common;
using Managing.Core;
using Managing.Domain.Statistics;
using Managing.Domain.Trades;
using Managing.Infrastructure.Evm.Models;

namespace Managing.Infrastructure.Evm.Services;

public class TradaoService : ITradaoService
{
    private readonly HttpClient _httpClient;

    public TradaoService()
    {
        _httpClient = new HttpClient();
    }

    public async Task<List<Trader>> GetBadTrader()
    {
        var bestTraders = await _httpClient.GetFromJsonAsync<TradaoList>(
            $"https://api.tradao.xyz/v2/td/dashboard/pnlTop/12/asc/604800/0/?exchangeId=gmx_42161&exchangeId=gmx_43114&exchangeId=gmxv2_42161&exchangeId=gmxv2_43114&current=1&limit=20&order=desc&window=2592000&exchangeDic=exchangeId%3Dgmx_42161%26exchangeId%3Dgmx_43114%26exchangeId%3Dgmxv2_42161%26exchangeId%3Dgmxv2_43114&chain=0&exchange=gmx&openPosition=0");

        if (bestTraders == null || bestTraders.row.Count == 0)
        {
            return new List<Trader>();
        }

        return await GetTraderDetails(bestTraders);
    }

    public async Task<List<Trader>> GetBestTrader()
    {
        var bestTraders = await _httpClient.GetFromJsonAsync<TradaoList>(
            $"https://api.tradao.xyz/v2/td/dashboard/roiTop/12/desc/2592000/0/?exchangeId=gmxv2_42161&current=1&limit=12&order=desc&window=2592000&exchangeDic=exchangeId%3Dgmxv2_42161&chain=42161&exchange=gmxv2&openPosition=0&volumeL=100000&tradeTimesL=10&tradeTimesH=50&winRateL=0.6");

        if (bestTraders == null || bestTraders.row.Count == 0)
        {
            return new List<Trader>();
        }

        return await GetTraderDetails(bestTraders);
    }

    public async Task<List<Trade>> GetTrades(string address)
    {
        var response =
            await _httpClient.GetFromJsonAsync<TradaoUserDetails>(
                $"https://api.tradao.xyz/v2/td/trader/insightsV2/{address}?exchangeId=gmx_42161&exchangeId=gmx_43114&exchangeId=gmxv2_42161&exchangeId=gmxv2_43114");

        var trades = new List<Trade>();

        if (response == null) return trades;

        foreach (var record in response.gmxv2_42161.records.Where(p => p.isOpen))
        {
            var computedData = GetComputedData(record.records);
            var marketPrice = response.gmxv2_42161.prices.FirstOrDefault(p => p.Key == record.indexToken).Value;

            var trade = new Trade(
                DateTime.UtcNow,
                record.isLong ? Common.Enums.TradeDirection.Long : Common.Enums.TradeDirection.Short,
                Common.Enums.TradeStatus.Filled,
                Common.Enums.TradeType.Market,
                TokenService.GetTicker(record.indexToken),
                Convert.ToDecimal(computedData.Collateral) / Convert.ToDecimal(marketPrice),
                Convert.ToDecimal(record.averagePrice),
                Convert.ToDecimal(computedData.Size) / Convert.ToDecimal(computedData.Collateral),
                record.positionId, record.liqPrice
            );

            trades.Add(trade);
        }

        return trades;
    }

    private (decimal Collateral, decimal Size) GetComputedData(List<RecordDetail> positionRecords)
    {
        decimal computedCollateral = 0;
        decimal computedSize = 0;

        foreach (var record in positionRecords)
        {
            if (record.eventType == 1) // Increase
            {
                computedCollateral += Convert.ToDecimal(record.collateralDelta);
                computedSize += Convert.ToDecimal(record.sizeDelta);
            }
            else if (record.eventType == 2) // Decrease
            {
                computedCollateral -= Convert.ToDecimal(record.collateralDelta);
                computedSize -= Convert.ToDecimal(record.sizeDelta);
            }
        }

        return (computedCollateral, computedSize);
    }


    private async Task<List<Trader>> GetTraderDetails(TradaoList traders)
    {
        var result = new List<Trader>();
        foreach (var trader in traders.row)
        {
            var response =
                await _httpClient.GetFromJsonAsync<TradaoUserDetails>(
                    $"https://api.tradao.xyz/v2/td/trader/insightsV2/{trader.user}?exchangeId=gmx_42161&exchangeId=gmx_43114&exchangeId=gmxv2_42161&exchangeId=gmxv2_43114");

            if (response != null)
                result.Add(Map(response, trader.user));
        }

        return result;
    }

    private Trader Map(TradaoUserDetails response, string address)
    {
        return new Trader
        {
            Address = address,
            Winrate = (int)(response.gmxv2_42161.summary.winRate * 100),
            Pnl = response.gmxv2_42161.summary.pnl,
            TradeCount = response.gmxv2_42161.summary.trades,
            AverageWin = response.gmxv2_42161.summary.averageWin,
            AverageLoss = response.gmxv2_42161.summary.averageLoss,
            Roi = response.gmxv2_42161.summary.roi * 100
        };
    }

    public async Task<List<FundingRate>> GetFundingRates()
    {
        _httpClient.DefaultRequestHeaders.Accept.Clear();
        _httpClient.DefaultRequestHeaders.Accept.Add(
            new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));

        var response =
            await _httpClient.GetFromJsonAsync<List<TradaoFundingRate>>("https://api.tradao.xyz/v1/td/fr/all");

        return Map(response);
    }

    private List<FundingRate> Map(List<TradaoFundingRate>? response)
    {
        if (response == null)
        {
            return new List<FundingRate>();
        }

        var result = new List<FundingRate>();

        foreach (var fundingRate in response)
        {
            var ticker = Map(fundingRate.Symbol);

            if (ticker == null || fundingRate.ExchangeName != "gmxv2")
                continue;

            if (!Constants.GMX.Config.DeltaNeutralTickers.Contains(ticker.Value))
                continue;

            var longRate = GetApy(fundingRate.LongFundingRate);
            var shortRate = GetApy(fundingRate.ShortFundingRate);
            result.Add(new FundingRate
            {
                Ticker = ticker.Value,
                Rate = longRate,
                Direction = Enums.TradeDirection.Long,
                Date = DateTimeOffset.FromUnixTimeSeconds(fundingRate.Timestamp).DateTime
            });

            result.Add(new FundingRate
            {
                Ticker = ticker.Value,
                Rate = shortRate,
                Direction = Enums.TradeDirection.Short,
                Date = DateTimeOffset.FromUnixTimeSeconds(fundingRate.Timestamp).DateTime
            });
        }

        return result;
    }

    private Enums.Ticker? Map(string fundingRateSymbol)
    {
        try
        {
            return MiscExtensions.ParseEnum<Enums.Ticker>(fundingRateSymbol);
        }
        catch (Exception e)
        {
            return null;
        }
    }

    public decimal GetApy(string fundingRate)
    {
        try
        {
            decimal rate = Convert.ToDecimal(fundingRate, System.Globalization.CultureInfo.InvariantCulture);
            return rate * 100 * 24 * 365;
        }
        catch (FormatException)
        {
            // Handle the case where conversion fails due to an incorrect format
            // Log the error, return 0, or handle as appropriate for your application
            return 0;
        }
    }

    public class TradaoFundingRate
    {
        public string Symbol { get; set; }
        public string ChainId { get; set; }
        public string ExchangeName { get; set; }
        public string LongFundingRate { get; set; }
        public string ShortFundingRate { get; set; }
        public long Timestamp { get; set; }
    }
}