using CryptoExchange.Net.Objects;
using FTX.Net.Enums;
using FTX.Net.Objects.Models;
using Managing.Core;
using Managing.Domain.Candles;
using Managing.Domain.Trades;
using static Managing.Common.Enums;

namespace Managing.Infrastructure.Exchanges.Helpers
{
    public static class FtxHelpers
    {
        public static string ToFtxTicker(Ticker ticker)
        {
            switch (ticker)
            {
                case Ticker.ADA:
                    return "ADA-PERP";
                case Ticker.APE:
                    return "APE-PERP";
                case Ticker.ALGO:
                    return "ALGO-PERP";
                case Ticker.ATOM:
                    return "ATOM-PERP";
                case Ticker.AVAX:
                    return "AVAX-PERP";
                case Ticker.BNB:
                    return "BNB-PERP";
                case Ticker.BTC:
                    return "BTC-PERP";
                case Ticker.BAL:
                    return "BAL-PERP";
                case Ticker.CHZ:
                    return "CHZ-PERP";
                case Ticker.COMP:
                    return "COMP-PERP";
                case Ticker.CRO:
                    return "CRO-PERP";
                case Ticker.CRV:
                    return "CRV-PERP";
                case Ticker.DOGE:
                    return "DOGE-PERP";
                case Ticker.DOT:
                    return "DOT-PERP";
                case Ticker.DYDX:
                    return "DYDX-PERP";
                case Ticker.ENS:
                    return "ENS-PERP";
                case Ticker.ETC:
                    return "ETC-PERP";
                case Ticker.ETH:
                    return "ETH-PERP";
                case Ticker.FIL:
                    return "FIL-PERP";
                case Ticker.FLM:
                    return "FLM-PERP";
                case Ticker.FTM:
                    return "FTM-PERP";
                case Ticker.GALA:
                    return "GALA-PERP";
                case Ticker.GRT:
                    return "GRT-PERP";
                case Ticker.KSM:
                    return "KSM-PERP";
                case Ticker.LDO:
                    return "LDO-PERP";
                case Ticker.LINK:
                    return "LINK-PERP";
                case Ticker.LRC:
                    return "LRC-PERP";
                case Ticker.LTC:
                    return "LTC-PERP";
                case Ticker.MANA:
                    return "MANA-PERP";
                case Ticker.MATIC:
                    return "MATIC-PERP";
                case Ticker.MKR:
                    return "MKR-PERP";
                case Ticker.NEAR:
                    return "NEAR-PERP";
                case Ticker.QTUM:
                    return "QTUM-PERP";
                case Ticker.REN:
                    return "REN-PERP";
                case Ticker.ROSE:
                    return "ROSE-PERP";
                case Ticker.RSR:
                    return "RSR-PERP";
                case Ticker.RUNE:
                    return "RUNE-PERP";
                case Ticker.SAND:
                    return "SAND-PERP";
                case Ticker.SOL:
                    return "SOL-PERP";
                case Ticker.SRM:
                    return "SRM-PERP";
                case Ticker.SUSHI:
                    return "SUSHI-PERP";
                case Ticker.THETA:
                    return "THETA-PERP";
                case Ticker.UNI:
                    return "UNI-PERP";
                case Ticker.XMR:
                    return "XMR-PERP";
                case Ticker.XRP:
                    return "XRP-PERP";
                case Ticker.XTZ:
                    return "XTZ-PERP";
                default:
                    break;
            }

            throw new NotImplementedException();
        }


        public static Trade Map(WebCallResult<FTXOrder> result, decimal? leverage = null)
        {
            var data = result.Data;

            if (data == null)
            {
                return new Trade(DateTime.Now, TradeDirection.None,
                    TradeStatus.Cancelled, TradeType.Market, Ticker.BTC, 0, 0, 0,
                    "", result.Error?.Message);
            }

            return new Trade(data.CreateTime,
                (data.Side == OrderSide.Buy) ? TradeDirection.Long : TradeDirection.Short,
                (TradeStatus)data.Status, (TradeType)data.Type, MiscExtensions.ParseEnum<Ticker>(data.Symbol),
                data.Quantity, data.AverageFillPrice ?? 0, leverage,
                data.ClientOrderId, "");
        }

        internal static Trade Map(WebCallResult<FTXTriggerOrder> ftxResult, decimal? leverage)
        {
            var data = ftxResult.Data;

            if (data == null)
            {
                return new Trade(DateTime.Now, TradeDirection.None,
                    TradeStatus.Cancelled, TradeType.Market, Ticker.BTC, 0, 0, 0,
                    "", ftxResult.Error?.Message);
            }

            return new Trade(data.CreateTime,
                (data.Side == OrderSide.Buy) ? TradeDirection.Long : TradeDirection.Short,
                (TradeStatus)data.Status, (TradeType)data.Type, MiscExtensions.ParseEnum<Ticker>(data.Symbol),
                data.Quantity, data.TriggerPrice ?? 0, leverage,
                Guid.NewGuid().ToString(), "");
        }

        public static OrderType FtxOrderTypeMap(TradeType tradeType)
        {
            switch (tradeType)
            {
                case TradeType.Limit:
                    return OrderType.Limit;
                case TradeType.Market:
                    return OrderType.Market;
                default:
                    return OrderType.Limit;
            }
        }

        public static Trade Map(FTXOrder data)
        {
            if (data == null)
                return null;

            return new Trade(data.CreateTime, TradeDirection.None,
                (TradeStatus)data.Status, (TradeType)data.Type, MiscExtensions.ParseEnum<Ticker>(data.Symbol),
                data.Quantity, data.AverageFillPrice ?? 0, 0,
                data.ClientOrderId, "");
        }

        public static Candle Map(
            FTXKline ftxKline,
            Ticker ticker,
            TradingExchanges exchange,
            Timeframe timeframe)
        {
            return new Candle
            {
                Date = ftxKline.OpenTime,
                Volume = ftxKline.Volume ?? 0,
                Close = ftxKline.ClosePrice,
                High = ftxKline.HighPrice,
                Low = ftxKline.LowPrice,
                Open = ftxKline.OpenPrice,
                Ticker = ticker.ToString(),
                OpenTime = ftxKline.OpenTime,
                Exchange = exchange,
                Timeframe = timeframe
            };
        }

        internal static KlineInterval Map(Timeframe interval) => interval switch
        {
            Timeframe.FiveMinutes => KlineInterval.FiveMinutes,
            Timeframe.FifteenMinutes => KlineInterval.FifteenMinutes,
            Timeframe.OneHour => KlineInterval.OneHour,
            Timeframe.FourHour => KlineInterval.FourHours,
            Timeframe.OneDay => KlineInterval.OneDay,
            _ => throw new NotImplementedException(),
        };

        internal static TriggerOrderType FtxTriggerOrderTypeMap(TradeType tradeType) => tradeType switch
        {
            TradeType.StopMarket => TriggerOrderType.Stop,
            TradeType.StopLimit => TriggerOrderType.Stop,
            TradeType.StopLoss => TriggerOrderType.Stop,
            TradeType.TakeProfit => TriggerOrderType.TakeProfit,
            TradeType.StopLossProfit => TriggerOrderType.Stop,
            TradeType.StopLossProfitLimit => TriggerOrderType.Stop,
            TradeType.StopLossLimit => TriggerOrderType.Stop,
            TradeType.TakeProfitLimit => TriggerOrderType.TakeProfit,
            TradeType.TrailingStop => TriggerOrderType.TrailingStop,
            TradeType.TrailingStopLimit => TriggerOrderType.TrailingStop,
            TradeType.StopLossAndLimit => TriggerOrderType.Stop,
            TradeType.SettlePosition => TriggerOrderType.Stop,
            _ => throw new NotImplementedException(),
        };

        internal static Orderbook Map(WebCallResult<FTXOrderbook> ftxOrderBook)
        {
            return new Orderbook()
            {
                Asks = Map(ftxOrderBook.Data.Asks),
                Bids = Map(ftxOrderBook.Data.Bids)
            };
        }

        private static List<OrderBookEntry> Map(IEnumerable<FTXOrderBookEntry> entry)
        {
            return entry.Select(ask => new OrderBookEntry() { Price = ask.Price, Quantity = ask.Quantity }).ToList();
        }
    }
}