using CryptoExchange.Net.Authentication;
using Kraken.Net.Clients;
using Kraken.Net.Interfaces.Clients;
using Kraken.Net.Objects.Options;
using Managing.Common;
using Managing.Domain.Accounts;
using Managing.Domain.Candles;
using Managing.Domain.Statistics;
using Managing.Domain.Trades;
using Managing.Infrastructure.Exchanges.Helpers;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using static Managing.Common.Enums;

namespace Managing.Infrastructure.Exchanges.Exchanges;

public class KrakenProcessor : BaseProcessor
{
    private ILogger<KrakenProcessor> _logger;
    private IKrakenRestClient _krakenClient;

    public KrakenProcessor(ILogger<KrakenProcessor> logger)
    {
        _logger = logger;
    }

    public override Task<bool> CancelOrder(Account account, Ticker ticker)
    {
        throw new NotImplementedException();
    }

    public override Enums.TradingExchanges Exchange() => Enums.TradingExchanges.Kraken;

    public override async Task<decimal> GetBalance(Account account, bool isForPaperTrading = false)
    {
        LoadClient(account);
        var balance = await _krakenClient.SpotApi.Account.GetBalancesAsync();
        balance.Data.TryGetValue("USDT", out decimal krakenBalance);
        return krakenBalance;
    }

    public override Task<List<Balance>> GetBalances(Account account, bool isForPaperTrading = false)
    {
        throw new NotImplementedException();
    }

    public override Candle GetCandle(Account account, Ticker ticker, DateTime date)
    {
        throw new NotImplementedException();
    }

    public override Task<List<Candle>> GetCandles(Account account, Ticker ticker, DateTime startDate,
        Timeframe interval)
    {
        throw new NotImplementedException();
    }

    public override decimal GetFee(Account account, bool isForPaperTrading = false)
    {
        throw new NotImplementedException();
    }

    public override Orderbook GetOrderbook(Account account, Ticker ticker)
    {
        throw new NotImplementedException();
    }

    public override Task<List<Trade>> GetOrders(Account account, Ticker ticker)
    {
        throw new NotImplementedException();
    }

    public override decimal GetPrice(Account account, Ticker ticker, DateTime date)
    {
        LoadClient(account);
        var krakenKline = _krakenClient.SpotApi.ExchangeData.GetKlinesAsync(ticker.ToString(),
            Kraken.Net.Enums.KlineInterval.OneMinute, date).Result.Data.Data.ToList()[0];
        return (krakenKline.HighPrice + krakenKline.ClosePrice) / 2;
    }

    public override Task<decimal> GetQuantityInPosition(Account account, Ticker ticker)
    {
        throw new NotImplementedException();
    }

    public override async Task<Trade> GetTrade(Account account, string order, Ticker ticker)
    {
        LoadClient(account);
        var krakenOrder = await _krakenClient.SpotApi.Trading.GetOrderAsync(order);
        return KrakenHelpers.Map(krakenOrder.Data.Values.First());
    }

    public override Task<Trade> GetTrade(string reference, string orderId, Ticker ticker)
    {
        throw new NotImplementedException();
    }

    public override Task<List<FundingRate>> GetFundingRates()
    {
        throw new NotImplementedException();
    }

    public override Task<IEnumerable<Position>> GetPositions(Account account)
    {
        throw new NotImplementedException();
    }

    public override async Task<List<Trade>> GetTrades(Account account, Ticker ticker)
    {
        LoadClient(account);
        var krakenOrder = await _krakenClient.SpotApi.Trading.GetOrdersAsync();
        return (List<Trade>)krakenOrder.Data.Select(o => KrakenHelpers.Map(o));
    }

    public override decimal GetVolume(Account account, Ticker ticker)
    {
        throw new NotImplementedException();
    }

    public override void LoadClient(Account account)
    {
        var credentials = new ApiCredentials(account.Key, account.Secret);
        var krakenConfig = new KrakenRestOptions()
        {
            ApiCredentials = credentials
        };
        _krakenClient = new KrakenRestClient((options) => { options.ApiCredentials = krakenConfig.ApiCredentials; });
    }

    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)
    {
        LoadClient(account);
        var trade = new Trade(DateTime.Now, direction, TradeStatus.PendingOpen, tradeType, ticker, quantity, price,
            leverage, "", "");
        trade.SetQuantity(quantity, 6);
        trade.SetPrice(price, 1);

        var order = await _krakenClient.SpotApi.Trading.PlaceOrderAsync(ticker.ToString(),
            direction != TradeDirection.Long ? Kraken.Net.Enums.OrderSide.Sell : Kraken.Net.Enums.OrderSide.Buy,
            KrakenHelpers.KrakenOrderTypeMap(tradeType),
            price: price,
            quantity: quantity,
            leverage: leverage);

        _logger.LogInformation("Exchange result : {0}", JsonConvert.SerializeObject(order));
        var krakenOrderExecuted = GetTrade(account, ((string[])order.Data.OrderIds)[0], ticker).Result;
        trade.SetStatus(krakenOrderExecuted.Status);
        trade.SetExchangeOrderId(krakenOrderExecuted.ExchangeOrderId);
        trade.SetMessage(krakenOrderExecuted.Message);
        return trade;
    }
}