using cAlgo.API;
using cAlgo.API.Indicators;

namespace cAlgo.Indicators
{
    // Indicator in a separate window, shows HMA A (fast HMA) and trade signals.
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class HmaSmaCrossoverSignal : Indicator
    {
        [Parameter("HMA A Period (Fast)", DefaultValue = 20, Group = "Periods")]
        public int HmaAPeriod { get; set; }

        [Parameter("HMA B Period (Slow)", DefaultValue = 250, Group = "Periods")]
        public int HmaBPeriod { get; set; }

        [Parameter("SMA C Period (Base)", DefaultValue = 200, Group = "Periods")]
        public int SmaCPeriod { get; set; }

        // Output for HMA A to provide context for signals
        [Output("HMA A", LineColor = "Cyan")]
        public IndicatorDataSeries HmaAOutput { get; set; }

        // Output for Buy signals
        [Output("Buy Signal", LineColor = "Green", PlotType = PlotType.Points, Thickness = 8)]
        public IndicatorDataSeries BuySignal { get; set; }

        // Output for Sell signals
        [Output("Sell Signal", LineColor = "Red", PlotType = PlotType.Points, Thickness = 8)]
        public IndicatorDataSeries SellSignal { get; set; }

        // Internal indicator references
        private HullMovingAverage _hmaA;
        private HullMovingAverage _hmaB;
        private SimpleMovingAverage _smaC;

        protected override void Initialize()
        {
            // Initialize the internal indicators using the close prices
            _hmaA = Indicators.HullMovingAverage(Bars.ClosePrices, HmaAPeriod);
            _hmaB = Indicators.HullMovingAverage(Bars.ClosePrices, HmaBPeriod);
            _smaC = Indicators.SimpleMovingAverage(Bars.ClosePrices, SmaCPeriod);
        }

        public override void Calculate(int index)
        {
            // Assign HMA A value to the output series for the current index
            HmaAOutput[index] = _hmaA.Result[index];

            // We need at least 3 bars (index, index-1, index-2) for peak/trough detection at index-1
            if (index < 2)
            {
                BuySignal[index] = double.NaN;
                SellSignal[index] = double.NaN;
                return;
            }

            // Get HMA A values for peak/trough detection
            double hmaA_curr = _hmaA.Result[index];
            double hmaA_prev = _hmaA.Result[index - 1];
            double hmaA_prev2 = _hmaA.Result[index - 2];
            
            // Get values for signal conditions (at index - 1)
            double hmaB_prev = _hmaB.Result[index - 1];
            double smaC_prev = _smaC.Result[index - 1];

            // Detect peak or trough at index - 1 (the last closed bar confirmed by the current bar)
            // A peak occurs if the middle bar (index-1) is higher than its neighbors (index-2 and index)
            bool isPeak = (hmaA_prev2 < hmaA_prev) && (hmaA_prev > hmaA_curr);
            // A trough occurs if the middle bar (index-1) is lower than its neighbors
            bool isTrough = (hmaA_prev2 > hmaA_prev) && (hmaA_prev < hmaA_curr);

            // Initialize signals for the current bar (index) to NaN
            BuySignal[index] = double.NaN;
            SellSignal[index] = double.NaN;

            // Reset signals at index - 1 (to handle repainting if the current bar 'index' changes)
            BuySignal[index - 1] = double.NaN;
            SellSignal[index - 1] = double.NaN;

            // --- Sell Signal Condition ---
            // B < C (Slow HMA below Base SMA)
            // A > C (Fast HMA above Base SMA)
            // A forms a peak (at index - 1)
            if ((hmaB_prev < smaC_prev) && (hmaA_prev > smaC_prev) && isPeak)
            {
                // Place the signal dot at the peak (index - 1) at the HMA A level
                SellSignal[index - 1] = hmaA_prev;
            }

            // --- Buy Signal Condition ---
            // B > C (Slow HMA above Base SMA)
            // A < C (Fast HMA below Base SMA)
            // A forms a trough (at index - 1)
            if ((hmaB_prev > smaC_prev) && (hmaA_prev < smaC_prev) && isTrough)
            {
                // Place the signal dot at the trough (index - 1) at the HMA A level
                BuySignal[index - 1] = hmaA_prev;
            }
        }
    }
}