using Managing.Core;
using Managing.Domain.Candles;
using Managing.Domain.Indicators;
using Managing.Domain.Shared.Rules;
using Managing.Domain.Strategies.Base;
using Skender.Stock.Indicators;
using static Managing.Common.Enums;

namespace Managing.Domain.Strategies.Trends;

public class StochRsiTrendIndicatorBase : IndicatorBase
{
    public List<LightSignal> Signals { get; set; }

    public StochRsiTrendIndicatorBase(
        string name,
        int period,
        int stochPeriod,
        int signalPeriod,
        int smoothPeriods) : base(name, IndicatorType.StochRsiTrend)
    {
        Signals = new List<LightSignal>();
        StochPeriods = stochPeriod;
        SignalPeriods = signalPeriod;
        SmoothPeriods = smoothPeriods;
        Period = period;
    }

    public override List<LightSignal> Run(HashSet<Candle> candles)
    {
        if (candles.Count <= 10 * Period + 50)
        {
            return null;
        }

        try
        {
            var stochRsi = candles
                .GetStochRsi(Period.Value, StochPeriods.Value, SignalPeriods.Value, SmoothPeriods.Value)
                .RemoveWarmupPeriods();
            var stochRsiCandles = MapStochRsiToCandle(stochRsi, candles.TakeLast(Period.Value));

            if (stochRsi.Count() == 0)
                return null;

            var previousCandle = stochRsiCandles[0];
            foreach (var currentCandle in stochRsiCandles.Skip(1))
            {
                if (currentCandle.Signal < 20)
                {
                    AddSignal(currentCandle, TradeDirection.Long, Confidence.None);
                }
                else if (currentCandle.Signal > 80)
                {
                    AddSignal(currentCandle, TradeDirection.Short, Confidence.None);
                }

                previousCandle = currentCandle;
            }

            return Signals.OrderBy(s => s.Date).ToList();
        }
        catch (RuleException)
        {
            return null;
        }
    }

    public override IndicatorsResultBase GetIndicatorValues(HashSet<Candle> candles)
    {
        return new IndicatorsResultBase()
        {
            StochRsi = candles.GetStochRsi(Period.Value, StochPeriods.Value, SignalPeriods.Value, SmoothPeriods.Value)
                .ToList()
        };
    }

    private List<CandleStochRsi> MapStochRsiToCandle(IEnumerable<StochRsiResult> ema, IEnumerable<Candle> candles)
    {
        var emaList = new List<CandleStochRsi>();
        foreach (var candle in candles)
        {
            var currentEma = ema.Find(candle.Date);
            if (currentEma != null)
            {
                emaList.Add(new CandleStochRsi()
                {
                    Close = candle.Close,
                    Open = candle.Open,
                    Date = candle.Date,
                    Ticker = candle.Ticker,
                    Exchange = candle.Exchange,
                    Signal = currentEma.Signal.Value,
                    StochRsi = currentEma.StochRsi.Value
                });
            }
        }

        return emaList;
    }

    private void AddSignal(CandleStochRsi candleSignal, TradeDirection direction, Confidence confidence)
    {
        var signal = new LightSignal(
            MiscExtensions.ParseEnum<Ticker>(candleSignal.Ticker),
            direction,
            confidence,
            candleSignal,
            candleSignal.Date,
            candleSignal.Exchange,
            Type,
            SignalType,
            Name);
        if (!Signals.Any(s => s.Identifier == signal.Identifier))
        {
            Signals.AddItem(signal);
        }
    }

    private class CandleStochRsi : Candle
    {
        public double Signal { get; internal set; }
        public double StochRsi { get; internal set; }
    }
}