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

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

    public StDevContext(string name, int period) : base(name, IndicatorType.StDev)
    {
        Signals = new List<LightSignal>();
        Period = period;
    }

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

        try
        {
            var stDev = candles.GetStdDev(Period.Value).ToList();
            var stDevCandles = MapStDev(stDev, candles.TakeLast(Period.Value));

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

            var lastCandle = stDevCandles.Last();
            var zScore = lastCandle.ZScore ?? 0;

            // Determine confidence based on Z-score ranges
            // Lower absolute Z-score = more normal volatility = higher confidence for trading
            // Higher absolute Z-score = more extreme volatility = lower confidence for trading
            Confidence confidence;

            if (Math.Abs(zScore) <= 0.5)
            {
                // Very low volatility - ideal conditions for trading
                confidence = Confidence.High;
            }
            else if (Math.Abs(zScore) <= 1.0)
            {
                // Normal volatility - good conditions for trading
                confidence = Confidence.Medium;
            }
            else if (Math.Abs(zScore) <= 1.5)
            {
                // Elevated volatility - caution advised
                confidence = Confidence.Low;
            }
            else
            {
                // High volatility - trading not recommended
                confidence = Confidence.None;
            }

            // Context strategies always return TradeDirection.None
            // The confidence level indicates the quality of market conditions
            AddSignal(lastCandle, TradeDirection.None, confidence);

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

    public override IndicatorsResultBase GetIndicatorValues(HashSet<Candle> candles)
    {
        var test = new IndicatorsResultBase()
        {
            StdDev = candles.GetStdDev(Period.Value).ToList()
        };

        return test;
    }

    private List<CandleStDev> MapStDev(List<StdDevResult> stDev, IEnumerable<Candle> candles)
    {
        var sctList = new List<CandleStDev>();
        foreach (var candle in candles)
        {
            var currentSct = stDev.Find(candle.Date);
            if (currentSct != null)
            {
                sctList.Add(new CandleStDev()
                {
                    Close = candle.Close,
                    Open = candle.Open,
                    Date = candle.Date,
                    Ticker = candle.Ticker,
                    Exchange = candle.Exchange,
                    StDev = currentSct.StdDev,
                    ZScore = currentSct.ZScore,
                    StdDevSma = currentSct.StdDevSma,
                    Mean = currentSct.Mean
                });
            }
        }

        return sctList;
    }

    private void AddSignal(CandleStDev 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 CandleStDev : Candle
    {
        public double? StDev { get; internal set; }
        public double? ZScore { get; internal set; }
        public double? StdDevSma { get; internal set; }
        public double? Mean { get; internal set; }
    }
}