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;

///<summary>
/// Lagging STC Strategy: Combines Schaff Trend Cycle with volatility-based confirmation.
/// Key Features:
///  1. Short signals on STC breakdown from overbught (75+ → ≤75) with recent compressed volatility (min >78)
///  2. Long signals on STC rebound from oversold (25- → ≥25) with recent compressed volatility (max <11)
///  3. Avoids look-ahead bias through proper rolling window implementation
/// </summary>
public class LaggingSTC : IndicatorBase
{
    public List<LightSignal> Signals { get; set; }

    public LaggingSTC(string name, int cyclePeriods, int fastPeriods, int slowPeriods) : base(name,
        IndicatorType.LaggingStc)
    {
        Signals = new List<LightSignal>();
        FastPeriods = fastPeriods;
        SlowPeriods = slowPeriods;
        CyclePeriods = cyclePeriods;
    }

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

        try
        {
            var stc = candles.GetStc(FastPeriods.Value, FastPeriods.Value, SlowPeriods.Value).ToList();
            var stcCandles = MapStcToCandle(stc, candles.TakeLast(CyclePeriods.Value * 3));

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

            for (int i = 1; i < stcCandles.Count; i++)
            {
                var currentCandle = stcCandles[i];
                var previousCandle = stcCandles[i - 1];

                /* VOLATILITY CONFIRMATION WINDOW
                 * - 22-period rolling window (≈1 trading month)
                 * - Ends at previous candle to avoid inclusion of current break
                 * - Dynamic sizing for early dataset cases */
                // Calculate the lookback window ending at previousCandle (excludes currentCandle)
                int windowSize = 40;
                int windowStart = Math.Max(0, i - windowSize); // Ensure no negative indices
                var lookbackWindow = stcCandles
                    .Skip(windowStart)
                    .Take(i - windowStart) // Take up to previousCandle (i-1)
                    .ToList();

                double? minStc = lookbackWindow.Min(c => c.Stc);
                double? maxStc = lookbackWindow.Max(c => c.Stc);

                // Short Signal: Break below 75 with prior min >78
                if (previousCandle.Stc > 75 && currentCandle.Stc <= 75)
                {
                    if (minStc > 78)
                    {
                        AddSignal(currentCandle, TradeDirection.Short, Confidence.Medium);
                    }
                }

                // Long Signal: Break above 25 with prior max <11
                if (previousCandle.Stc < 25 && currentCandle.Stc >= 25)
                {
                    if (maxStc < 11)
                    {
                        AddSignal(currentCandle, TradeDirection.Long, Confidence.Medium);
                    }
                }
            }

            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 stc = candles.GetStc(FastPeriods.Value, FastPeriods.Value, SlowPeriods.Value).ToList();
        return new IndicatorsResultBase
        {
            Stc = stc
        };
    }

    private List<CandleSct> MapStcToCandle(List<StcResult> stc, IEnumerable<Candle> candles)
    {
        var sctList = new List<CandleSct>();
        foreach (var candle in candles)
        {
            var currentSct = stc.Find(candle.Date);
            if (currentSct != null)
            {
                sctList.Add(new CandleSct()
                {
                    Close = candle.Close,
                    Open = candle.Open,
                    Date = candle.Date,
                    Ticker = candle.Ticker,
                    Exchange = candle.Exchange,
                    Stc = currentSct.Stc
                });
            }
        }

        return sctList;
    }

    private void AddSignal(CandleSct 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 CandleSct : Candle
    {
        public double? Stc { get; internal set; }
    }
}