using Managing.Application.Abstractions.Repositories;
using Managing.Common;
using Managing.Domain.Accounts;
using Managing.Domain.Candles;
using Managing.Domain.Evm;
using Managing.Domain.Statistics;
using Managing.Domain.Trades;
using Microsoft.Extensions.Logging;
using static Managing.Common.Enums;

namespace Managing.Infrastructure.Exchanges.Exchanges;

public class EvmProcessor : BaseProcessor
{
    public override TradingExchanges Exchange() => TradingExchanges.Evm;

    private ILogger<EvmProcessor> _logger;
    private IEvmManager _evmManager;

    public EvmProcessor(ILogger<EvmProcessor> logger, IEvmManager evmManager)
    {
        _logger = logger;
        _evmManager = evmManager;
    }

    public override async Task<bool> CancelOrder(Account account, Ticker ticker)
    {
        return await _evmManager.CancelOrders(account, ticker);
    }


    public override async Task<decimal> GetBalance(Account account, bool isForPaperTrading = false)
    {
        //var balances = await _evmManager.GetAllBalancesOnAllChain(account.Key);
        //var balanceAmount = 0m;

        //foreach (var balance in balances)
        //{
        //    balanceAmount += balance.Value;
        //}

        var evmBalance = await _evmManager.GetTokenBalance(Constants.Chains.Arbitrum, Ticker.USDC, account.Key);
        return evmBalance.Balance;
    }

    public override async Task<List<Balance>> GetBalances(Account account, bool isForPaperTrading = false)
    {
        var balances = await _evmManager.GetAllBalancesOnAllChain(account.Key);
        return Map(balances);
    }

    private List<Balance> Map(List<EvmBalance> balances)
    {
        return balances.ConvertAll(balance => new Balance
        {
            TokenName = balance.TokenName,
            Price = balance.Price,
            Value = balance.Value,
            Amount = balance.Balance,
            TokenAdress = balance.TokenAddress,
            Chain = balance.Chain
        });
    }

    public override async Task<Candle> GetCandle(Account account, Ticker ticker, DateTime date)
    {
        return await _evmManager.GetCandle(ticker);
    }

    public override async Task<List<Candle>> GetCandles(Account account, Ticker ticker, DateTime startDate,
        Timeframe interval)
    {
        return await _evmManager.GetCandles(ticker, startDate, interval);
    }

    public async Task<List<Candle>> GetCandles(Account account, Ticker ticker, DateTime startDate, Timeframe interval, bool isFirstCall)
    {
        return await _evmManager.GetCandles(ticker, startDate, interval, isFirstCall);
    }

    public override decimal GetFee(Account account, bool isForPaperTrading = false)
    {
        return _evmManager.GetFee(Constants.Chains.Arbitrum).Result;
    }

    public override async Task<decimal> GetPrice(Account account, Ticker ticker, DateTime date)
    {
        return (await GetCandles(account, ticker, date, Timeframe.OneMinute, true)).Last().Close;
    }

    public override async Task<decimal> GetQuantityInPosition(Account account, Ticker ticker)
    {
        return await _evmManager.QuantityInPosition(Constants.Chains.Arbitrum, account, ticker);
    }

    public override async Task<Trade> GetTrade(Account account, string order, Ticker ticker)
    {
        return await _evmManager.GetTrade(account, Constants.Chains.Arbitrum, ticker);
    }

    public override async Task<Trade> GetTrade(string reference, string orderId, Ticker ticker)
    {
        return await _evmManager.GetTrade(reference, Constants.Chains.Arbitrum, ticker);
    }

    public override async Task<List<FundingRate>> GetFundingRates()
    {
        return await _evmManager.GetFundingRates();
    }

    public override async Task<IEnumerable<Position>> GetPositions(Account account)
    {
        return await _evmManager.GetPositions(account);        
    }

    public override decimal GetVolume(Account account, Ticker ticker)
    {
        var volume = _evmManager.GetVolume(SubgraphProvider.ChainlinkPrice, ticker);
        return volume;
    }

    public override async Task<Trade> OpenTrade(
        Account account,
        Ticker ticker,
        TradeDirection direction,
        decimal price,
        decimal quantity,
        decimal? leverage = null,
        TradeType tradeType = TradeType.Limit,
        bool reduceOnly = false,
        bool isForPaperTrading = false,
        DateTime? currentDate = null,
        bool ioc = true,
        decimal? stopLossPrice = null,
        decimal? takeProfitPrice = null)
    {
        Trade trade;
        if (reduceOnly)
        {
            if (tradeType is TradeType.TakeProfit
                or TradeType.StopLoss)
            {
                // If trade type is TP or SL we create DecreaseOrder
                trade = await _evmManager.DecreaseOrder(account, tradeType, ticker, direction, price, quantity,
                    leverage);
            }
            else
            {
                // Trade requested is not an SL nor TP 
                // Price is the current price
                // We create Decrease position
                trade = await _evmManager.DecreasePosition(account, ticker, direction, price, quantity, leverage);
            }
        }
        else
        {
            trade = await _evmManager.IncreasePosition(account, ticker, direction, price, quantity, leverage,
                stopLossPrice, takeProfitPrice);
        }

        return trade;
    }

    public override async Task<List<Trade>> GetOrders(Account account, Ticker ticker)
    {
        return await _evmManager.GetOrders(account, ticker);
    }


    #region Not implemented

    public override void LoadClient(Account account)
    {
        // No client needed
        throw new NotImplementedException();
    }

    public override async Task<List<Trade>> GetTrades(Account account, Ticker ticker)
    {
        // Use by commandHandler to get trades list 
        throw new NotImplementedException();
    }

    public override Orderbook GetOrderbook(Account account, Ticker ticker)
    {
        // Not use because EVM do not based on an orderbook
        throw new NotImplementedException();
    }

    #endregion
}