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.Signals;

public class DualEmaCrossIndicatorBase : EmaBaseIndicatorBase
{
    public List<LightSignal> Signals { get; set; }

    public DualEmaCrossIndicatorBase(string name, int fastPeriod, int slowPeriod) : base(name,
        IndicatorType.DualEmaCross)
    {
        Signals = new List<LightSignal>();
        FastPeriods = fastPeriod;
        SlowPeriods = slowPeriod;
        MinimumHistory = Math.Max(fastPeriod, slowPeriod) * 2;
    }

    public override IndicatorsResultBase GetIndicatorValues(HashSet<Candle> candles)
    {
        return new IndicatorsResultBase()
        {
            FastEma = candles.GetEma(FastPeriods.Value).ToList(),
            SlowEma = candles.GetEma(SlowPeriods.Value).ToList()
        };
    }

    public override List<LightSignal> Run(HashSet<Candle> candles)
    {
        if (candles.Count <= MinimumHistory)
        {
            return null;
        }

        try
        {
            var fastEma = candles.GetEma(FastPeriods.Value).ToList();
            var slowEma = candles.GetEma(SlowPeriods.Value).ToList();

            var dualEmaCandles = MapDualEmaToCandle(fastEma, slowEma, candles.TakeLast(MinimumHistory));

            if (dualEmaCandles.Count < 2)
                return null;

            var previousCandle = dualEmaCandles[0];
            foreach (var currentCandle in dualEmaCandles.Skip(1))
            {
                // Short signal: Fast EMA crosses below Slow EMA
                if (previousCandle.FastEma > previousCandle.SlowEma &&
                    currentCandle.FastEma < currentCandle.SlowEma)
                {
                    AddSignal(currentCandle, TradeDirection.Short, Confidence.Medium);
                }

                // Long signal: Fast EMA crosses above Slow EMA
                if (previousCandle.FastEma < previousCandle.SlowEma &&
                    currentCandle.FastEma > currentCandle.SlowEma)
                {
                    AddSignal(currentCandle, TradeDirection.Long, Confidence.Medium);
                }

                previousCandle = currentCandle;
            }

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

    private List<CandleDualEma> MapDualEmaToCandle(List<EmaResult> fastEma, List<EmaResult> slowEma,
        IEnumerable<Candle> candles)
    {
        var dualEmaList = new List<CandleDualEma>();
        foreach (var candle in candles)
        {
            var currentFastEma = fastEma.Find(candle.Date);
            var currentSlowEma = slowEma.Find(candle.Date);

            if (currentFastEma != null && currentFastEma.Ema.HasValue &&
                currentSlowEma != null && currentSlowEma.Ema.HasValue)
            {
                dualEmaList.Add(new CandleDualEma()
                {
                    Close = candle.Close,
                    Open = candle.Open,
                    Date = candle.Date,
                    Ticker = candle.Ticker,
                    Exchange = candle.Exchange,
                    FastEma = currentFastEma.Ema.Value,
                    SlowEma = currentSlowEma.Ema.Value,
                });
            }
        }

        return dualEmaList;
    }

    private void AddSignal(CandleDualEma 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);
        }
    }

    public class CandleDualEma : Candle
    {
        public double FastEma { get; set; }
        public double SlowEma { get; set; }
    }
}