using Managing.Core;
using Managing.Domain.Candles;
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 ChandelierExitStrategy : Strategy
{
    public List<Signal> Signals { get; set; }

    public ChandelierExitStrategy(string name, int period, double multiplier) : base(name, StrategyType.ChandelierExit)
    {
        Signals = new List<Signal>();
        Period = period;
        Multiplier = multiplier;
        MinimumHistory = 1 + Period.Value;
    }

    public override List<Signal> Run()
    {
        if (Candles.Count <= MinimumHistory)
        {
            return null;
        }

        try
        {
            GetSignals(ChandelierType.Long);
            GetSignals(ChandelierType.Short);

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

    public override StrategiesResultBase GetStrategyValues()
    {
        return new StrategiesResultBase()
        {
            ChandelierLong = Candles.GetChandelier(Period.Value, Multiplier.Value, ChandelierType.Long).ToList(),
            ChandelierShort = Candles.GetChandelier(Period.Value, Multiplier.Value, ChandelierType.Short).ToList()
        };
    }

    private void GetSignals(ChandelierType chandelierType)
    {
        var chandelier = Candles.GetChandelier(Period.Value, Multiplier.Value, chandelierType)
            .Where(s => s.ChandelierExit.HasValue).ToList();
        var chandelierCandle = MapChandelierToCandle(chandelier, Candles.TakeLast(MinimumHistory));
        var previousCandle = chandelierCandle[0];

        foreach (var currentCandle in chandelierCandle.Skip(1))
        {
            // Short
            if (currentCandle.Close < previousCandle.ChandelierExit &&
                previousCandle.Close > previousCandle.ChandelierExit &&
                currentCandle.Close < previousCandle.Open &&
                chandelierType == ChandelierType.Short)
            {
                AddSignal(currentCandle, TradeDirection.Short, Confidence.Medium);
            }

            // Long
            if (currentCandle.Close > previousCandle.ChandelierExit &&
                previousCandle.Close < previousCandle.ChandelierExit &&
                currentCandle.Close > currentCandle.Open &&
                chandelierType == ChandelierType.Long)
            {
                AddSignal(currentCandle, TradeDirection.Long, Confidence.Medium);
            }

            previousCandle = currentCandle;
        }
    }

    private List<CandleChandelier> MapChandelierToCandle(List<ChandelierResult> superTrend, IEnumerable<Candle> candles)
    {
        var superTrends = new List<CandleChandelier>();
        foreach (var candle in candles)
        {
            var currentChandelier = superTrend.Find(candle.Date);
            if (currentChandelier != null)
            {
                superTrends.Add(new CandleChandelier()
                {
                    Close = candle.Close,
                    Open = candle.Open,
                    Date = candle.Date,
                    Ticker = candle.Ticker,
                    Exchange = candle.Exchange,
                    ChandelierExit = (decimal)currentChandelier.ChandelierExit.Value,
                });
            }
        }

        return superTrends;
    }

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


    private class CandleChandelier : Candle
    {
        public decimal ChandelierExit { get; internal set; }
    }
}