using Managing.Application.Abstractions.Services;
using Managing.Domain.Accounts;
using Managing.Domain.Strategies;
using Managing.Domain.Strategies.Signals;
using Managing.Domain.Strategies.Trends;
using Xunit;
using static Managing.Common.Enums;

namespace Managing.Application.Tests
{
    public class StrategyTests
    {
        private readonly IExchangeService _exchangeService;

        public StrategyTests()
        {
            _exchangeService = TradingBaseTests.GetExchangeService();
        }

        [Theory]
        [InlineData(TradingExchanges.Binance, Ticker.ADA, Timeframe.OneDay)]
        public void Should_Return_Signal_On_Rsi_BullishDivergence2(TradingExchanges exchange, Ticker ticker,
            Timeframe timeframe)
        {
            var account = GetAccount(exchange);
            // Arrange
            var rsiStrategy = new RsiDivergenceStrategy("unittest", 5);
            var candles = _exchangeService.GetCandles(account, ticker, DateTime.Now.AddDays(-50), timeframe).Result;
            var resultSignal = new List<Signal>();

            // Act
            foreach (var candle in candles)
            {
                rsiStrategy.Candles.Enqueue(candle);
                var signals = rsiStrategy.Run();
            }

            if (rsiStrategy.Signals != null && rsiStrategy.Signals.Count > 0)
                resultSignal.AddRange(rsiStrategy.Signals);

            // Assert 
            Assert.IsType<List<Signal>>(resultSignal);
            Assert.Contains(resultSignal, s => s.Direction == TradeDirection.Long);
        }

        private static Account GetAccount(TradingExchanges exchange)
        {
            return new Account()
            {
                Exchange = exchange
            };
        }

        [Theory]
        [InlineData(TradingExchanges.Binance, Ticker.ADA, Timeframe.OneDay)]
        public void Shoud_Return_Signal_On_Rsi_BearishDivergence(TradingExchanges exchange, Ticker ticker,
            Timeframe timeframe)
        {
            // Arrange
            var account = GetAccount(exchange);
            var rsiStrategy = new RsiDivergenceStrategy("unittest", 5);
            var candles = _exchangeService.GetCandles(account, ticker, DateTime.Now.AddDays(-50), timeframe).Result;
            var resultSignal = new List<Signal>();

            // Act
            foreach (var candle in candles)
            {
                rsiStrategy.Candles.Enqueue(candle);
                var signals = rsiStrategy.Run();
            }

            if (rsiStrategy.Signals != null && rsiStrategy.Signals.Count > 0)
                resultSignal.AddRange(rsiStrategy.Signals);

            // Assert 
            Assert.IsType<List<Signal>>(resultSignal);
            Assert.Contains(resultSignal, s => s.Direction == TradeDirection.Short);
        }


        [Theory]
        [InlineData(TradingExchanges.Ftx, Ticker.ADA, Timeframe.OneDay, -500)]
        public async Task Shoud_Return_Signal_On_Macd_Cross(TradingExchanges exchange, Ticker ticker,
            Timeframe timeframe, int days)
        {
            // Arrange
            var account = GetAccount(exchange);
            var rsiStrategy = new MacdCrossStrategy("unittest", 12, 26, 9);
            var candles = await _exchangeService.GetCandles(account, ticker, DateTime.Now.AddDays(days), timeframe);
            var resultSignal = new List<Signal>();

            // Act
            foreach (var candle in candles)
            {
                rsiStrategy.Candles.Enqueue(candle);
                var signals = rsiStrategy.Run();
            }

            if (rsiStrategy.Signals != null && rsiStrategy.Signals.Count > 0)
                resultSignal.AddRange(rsiStrategy.Signals);

            // Assert 
            Assert.IsType<List<Signal>>(resultSignal);
            Assert.Contains(resultSignal, s => s.Direction == TradeDirection.Short);
            Assert.Contains(resultSignal, s => s.Direction == TradeDirection.Long);
        }

        [Theory]
        [InlineData(TradingExchanges.Ftx, Ticker.ADA, Timeframe.OneDay, -500)]
        public void Shoud_Return_Signal_On_SuperTrend(TradingExchanges exchange, Ticker ticker, Timeframe timeframe,
            int days)
        {
            // Arrange
            var account = GetAccount(exchange);
            var superTrendStrategy = new SuperTrendStrategy("unittest", 10, 3);
            var candles = _exchangeService.GetCandles(account, ticker, DateTime.Now.AddDays(days), timeframe).Result;
            var resultSignal = new List<Signal>();

            // Act
            foreach (var candle in candles)
            {
                superTrendStrategy.Candles.Enqueue(candle);
                var signals = superTrendStrategy.Run();
            }

            if (superTrendStrategy.Signals != null && superTrendStrategy.Signals.Count > 0)
                resultSignal.AddRange(superTrendStrategy.Signals);

            // Assert 
            Assert.IsType<List<Signal>>(resultSignal);
            Assert.Contains(resultSignal, s => s.Direction == TradeDirection.Short);
            Assert.Contains(resultSignal, s => s.Direction == TradeDirection.Long);
        }

        [Theory]
        [InlineData(TradingExchanges.Ftx, Ticker.ADA, Timeframe.OneDay, -500)]
        public void Shoud_Return_Signal_On_ChandelierExist(TradingExchanges exchange, Ticker ticker,
            Timeframe timeframe, int days)
        {
            // Arrange
            var account = GetAccount(exchange);
            var chandelierExitStrategy = new ChandelierExitStrategy("unittest", 22, 3);
            var candles = _exchangeService.GetCandles(account, ticker, DateTime.Now.AddDays(days), timeframe, false)
                .Result;
            var resultSignal = new List<Signal>();

            // Act
            foreach (var candle in candles)
            {
                chandelierExitStrategy.Candles.Enqueue(candle);
                var signals = chandelierExitStrategy.Run();
            }

            if (chandelierExitStrategy.Signals is { Count: > 0 })
                resultSignal.AddRange(chandelierExitStrategy.Signals);

            // Assert 
            Assert.IsType<List<Signal>>(resultSignal);
            Assert.Contains(resultSignal, s => s.Direction == TradeDirection.Short);
            Assert.Contains(resultSignal, s => s.Direction == TradeDirection.Long);
        }

        [Theory]
        [InlineData(TradingExchanges.Ftx, Ticker.ADA, Timeframe.OneDay, -500)]
        public void Shoud_Return_Signal_On_EmaTrend(TradingExchanges exchange, Ticker ticker, Timeframe timeframe,
            int days)
        {
            // Arrange
            var account = GetAccount(exchange);
            var emaTrendSrategy = new EmaTrendStrategy("unittest", 200);
            var candles = _exchangeService.GetCandles(account, ticker, DateTime.Now.AddDays(days), timeframe).Result;
            var resultSignal = new List<Signal>();

            // Act
            foreach (var candle in candles)
            {
                emaTrendSrategy.Candles.Enqueue(candle);
                var signals = emaTrendSrategy.Run();
            }

            if (emaTrendSrategy.Signals != null && emaTrendSrategy.Signals.Count > 0)
                resultSignal.AddRange(emaTrendSrategy.Signals);

            // Assert 
            Assert.IsType<List<Signal>>(resultSignal);
            Assert.Contains(resultSignal, s => s.Direction == TradeDirection.Short);
            Assert.Contains(resultSignal, s => s.Direction == TradeDirection.Long);
        }


        [Theory]
        [InlineData(TradingExchanges.Evm, Ticker.BTC, Timeframe.FifteenMinutes, -50)]
        public void Shoud_Return_Signal_On_StochRsi(TradingExchanges exchange, Ticker ticker, Timeframe timeframe,
            int days)
        {
            // Arrange
            var account = GetAccount(exchange);
            var stochRsiStrategy = new StochRsiTrendStrategy("unittest", 14, 14, 3, 1);
            var candles = _exchangeService.GetCandles(account, ticker, DateTime.Now.AddDays(days), timeframe).Result;
            var resultSignal = new List<Signal>();

            // var json = JsonConvert.SerializeObject(candles);
            // File.WriteAllText($"{ticker.ToString()}-{timeframe.ToString()}-candles.json", json);
            // var json2 = FileHelpers.ReadJson<List<Candle>>($"{ticker.ToString()}-{timeframe.ToString()}-candles.json");

            // Act
            foreach (var candle in candles)
            {
                stochRsiStrategy.Candles.Enqueue(candle);
                var signals = stochRsiStrategy.Run();
            }

            if (stochRsiStrategy.Signals != null && stochRsiStrategy.Signals.Count > 0)
                resultSignal.AddRange(stochRsiStrategy.Signals);

            // Assert 
            Assert.IsType<List<Signal>>(resultSignal);
            Assert.Contains(resultSignal, s => s.Direction == TradeDirection.Short);
            Assert.Contains(resultSignal, s => s.Direction == TradeDirection.Long);
        }
    }
}