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

    public SuperTrendCrossEma(string name, int period, double multiplier) : base(name, IndicatorType.SuperTrendCrossEma)
    {
        Signals = new List<LightSignal>();
        Period = period;
        Multiplier = multiplier;
        MinimumHistory = 100 + Period.Value;
    }

    public override List<LightSignal> Run(HashSet<Candle> candles)
    {
        // Validate sufficient historical data for all indicators
        const int emaPeriod = 50;
        const int adxPeriod = 14; // Standard ADX period
        const int adxThreshold = 25; // Minimum ADX level to confirm a trend

        int minimumRequiredHistory = Math.Max(Math.Max(emaPeriod, adxPeriod), Period.Value * 2); // Ensure enough data
        if (candles.Count < minimumRequiredHistory)
        {
            return null;
        }

        try
        {
            // 1. Calculate indicators
            var superTrend = candles.GetSuperTrend(Period.Value, Multiplier.Value)
                .Where(s => s.SuperTrend.HasValue)
                .ToList();

            var ema50 = candles.GetEma(emaPeriod)
                .Where(e => e.Ema.HasValue)
                .ToList();

            var adxResults = candles.GetAdx(adxPeriod)
                .Where(a => a.Adx.HasValue && a.Pdi.HasValue && a.Mdi.HasValue) // Ensure all values exist
                .ToList();

            // 2. Create merged dataset with price + indicators
            var superTrendCandles = MapSuperTrendToCandle(superTrend, candles.TakeLast(minimumRequiredHistory));
            if (superTrendCandles.Count == 0)
                return null;

            // 3. Add EMA50 and ADX values to the CandleSuperTrend objects
            foreach (var candle in superTrendCandles)
            {
                var emaValue = ema50.Find(e => e.Date == candle.Date)?.Ema;
                var adxValue = adxResults.Find(a => a.Date == candle.Date);

                if (emaValue.HasValue)
                    candle.Ema50 = emaValue.Value;

                if (adxValue != null)
                {
                    candle.Adx = (decimal)adxValue.Adx.Value;
                    candle.Pdi = (decimal)adxValue.Pdi.Value;
                    candle.Mdi = (decimal)adxValue.Mdi.Value;
                }
            }

            // 4. Signal detection logic with ADX filter
            for (int i = 1; i < superTrendCandles.Count; i++)
            {
                var current = superTrendCandles[i];
                var previous = superTrendCandles[i - 1];

                // Convert SuperTrend to double for comparison
                double currentSuperTrend = (double)current.SuperTrend;
                double previousSuperTrend = (double)previous.SuperTrend;

                // Ensure ADX data exists
                if (current.Adx < adxThreshold) // Only trade when ADX confirms trend strength
                    continue;

                /* LONG SIGNAL CONDITIONS:
                 * 1. SuperTrend crosses above EMA50
                 * 2. Price > SuperTrend and > EMA50
                 * 3. Previous state shows SuperTrend < EMA50
                 * 4. ADX > threshold and +DI > -DI (bullish momentum)
                 */
                bool longCross = currentSuperTrend > current.Ema50 &&
                                 previousSuperTrend < previous.Ema50;

                bool longPricePosition = current.Close > (decimal)currentSuperTrend &&
                                         current.Close > (decimal)current.Ema50;

                bool adxBullish = current.Pdi > current.Mdi; // Bullish momentum confirmation

                if (longCross && longPricePosition && adxBullish)
                {
                    AddSignal(current, TradeDirection.Long, Confidence.Medium);
                }

                /* SHORT SIGNAL CONDITIONS:
                 * 1. SuperTrend crosses below EMA50
                 * 2. Price < SuperTrend and < EMA50
                 * 3. Previous state shows SuperTrend > EMA50
                 * 4. ADX > threshold and -DI > +DI (bearish momentum)
                 */
                bool shortCross = currentSuperTrend < current.Ema50 &&
                                  previousSuperTrend > previous.Ema50;

                bool shortPricePosition = current.Close < (decimal)currentSuperTrend &&
                                          current.Close < (decimal)current.Ema50;

                bool adxBearish = current.Mdi > current.Pdi; // Bearish momentum confirmation

                if (shortCross && shortPricePosition && adxBearish)
                {
                    AddSignal(current, TradeDirection.Short, Confidence.Medium);
                }
            }

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

    private List<CandleSuperTrend> MapSuperTrendToCandle(List<SuperTrendResult> superTrend, IEnumerable<Candle> candles)
    {
        var superTrends = new List<CandleSuperTrend>();
        foreach (var candle in candles)
        {
            var currentSuperTrend = superTrend.Find(candle.Date);
            if (currentSuperTrend != null)
            {
                superTrends.Add(new CandleSuperTrend()
                {
                    Close = candle.Close,
                    Open = candle.Open,
                    Date = candle.Date,
                    Ticker = candle.Ticker,
                    Exchange = candle.Exchange,
                    SuperTrend = currentSuperTrend.SuperTrend.Value,
                    LowerBand = currentSuperTrend.LowerBand,
                    UpperBand = currentSuperTrend.UpperBand,
                });
            }
        }

        return superTrends;
    }

    public override IndicatorsResultBase GetIndicatorValues(HashSet<Candle> candles)
    {
        return new IndicatorsResultBase()
        {
            SuperTrend = candles.GetSuperTrend(Period.Value, Multiplier.Value).Where(s => s.SuperTrend.HasValue)
                .ToList()
        };
    }


    private void AddSignal(CandleSuperTrend 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 CandleSuperTrend : Candle
    {
        public decimal SuperTrend { get; internal set; }
        public decimal? LowerBand { get; internal set; }
        public decimal? UpperBand { get; internal set; }
        public double Ema50 { get; set; }
        public decimal Adx { get; set; } // ADX value
        public decimal Pdi { get; set; } // Positive Directional Indicator (+DI)
        public decimal Mdi { get; set; } // Negative Directional Indicator (-DI)
    }
}