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 MacdCrossIndicatorBase : IndicatorBase
{
    public List<LightSignal> Signals { get; set; }

    public MacdCrossIndicatorBase(string name, int fastPeriods, int slowPeriods, int signalPeriods) :
        base(name, IndicatorType.MacdCross)
    {
        Signals = new List<LightSignal>();
        FastPeriods = fastPeriods;
        SlowPeriods = slowPeriods;
        SignalPeriods = signalPeriods;
    }

    public override List<LightSignal> Run(HashSet<Candle> candles)
    {
        if (candles.Count <= 2 * (SlowPeriods + SignalPeriods))
        {
            return null;
        }

        try
        {
            var macd = candles.GetMacd(FastPeriods.Value, SlowPeriods.Value, SignalPeriods.Value).ToList();
            var macdCandle = MapMacdToCandle(macd, candles.TakeLast(SignalPeriods.Value));

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

            var previousCandle = macdCandle[0];
            foreach (var currentCandle in macdCandle.Skip(1))
            {
                // // Only trigger signals when Signal line is outside -100 to 100 range (extreme conditions)
                // if (currentCandle.Signal < -200 || currentCandle.Signal > 200)
                // {
                //    
                // }

                // Check for MACD line crossing below Signal line (bearish cross)
                if (previousCandle.Macd > previousCandle.Signal && currentCandle.Macd < currentCandle.Signal)
                {
                    AddSignal(currentCandle, TradeDirection.Short, Confidence.Medium);
                }

                // Check for MACD line crossing above Signal line (bullish cross)
                if (previousCandle.Macd < previousCandle.Signal && currentCandle.Macd > currentCandle.Signal)
                {
                    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;
        }
    }

    public override IndicatorsResultBase GetIndicatorValues(HashSet<Candle> candles)
    {
        return new IndicatorsResultBase()
        {
            Macd = candles.GetMacd(FastPeriods.Value, SlowPeriods.Value, SignalPeriods.Value).ToList()
        };
    }


    private List<CandleMacd> MapMacdToCandle(List<MacdResult> macd, IEnumerable<Candle> candles)
    {
        var macdList = new List<CandleMacd>();
        foreach (var candle in candles)
        {
            var currentMacd = macd.Find(candle.Date);
            if (currentMacd != null)
            {
                macdList.Add(new CandleMacd()
                {
                    Close = candle.Close,
                    Open = candle.Open,
                    Date = candle.Date,
                    Ticker = candle.Ticker,
                    Exchange = candle.Exchange,
                    Macd = currentMacd.Macd.Value,
                    Histogram = currentMacd.Histogram.Value,
                    Signal = currentMacd.Signal.Value
                });
            }
        }

        return macdList;
    }

    private void AddSignal(CandleMacd 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 CandleMacd : Candle
    {
        public double Macd { get; set; }
        public double Signal { get; set; }
        public double Histogram { get; set; }
    }
}