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

namespace cAlgo.Robots
{
    [Robot(AccessRights = AccessRights.None)]
    public class HmaKcBot : Robot
    {
        [Parameter("HMA Period", DefaultValue = 250)]
        public int HmaPeriod { get; set; }

        [Parameter("KC MA Period", DefaultValue = 20)]
        public int KcMaPeriod { get; set; }

        [Parameter("KC ATR Period", DefaultValue = 20)]
        public int KcAtrPeriod { get; set; }

        [Parameter("KC Multiplier", DefaultValue = 2.0)]
        public double KcMultiplier { get; set; }

        [Parameter("Risk Percentage", DefaultValue = 1.0, MinValue = 0.1, MaxValue = 10.0)]
        public double RiskPercentage { get; set; }

        [Parameter("Stop Loss (pips)", DefaultValue = 20, MinValue = 1)]
        public double StopLossPips { get; set; }

        private HullMovingAverage _hma;
        private KeltnerChannels _kc;
        private const string Label = "HmaKcBot";

        protected override void OnStart()
        {
            _hma = Indicators.HullMovingAverage(Bars.ClosePrices, HmaPeriod);
            _kc = Indicators.KeltnerChannels(KcMaPeriod, MovingAverageType.Simple, KcAtrPeriod, MovingAverageType.Hull, KcMultiplier);
        }

        protected override void OnBar()
        {
            var hmaCurrent = _hma.Result.Last(1);
            var hmaPrevious = _hma.Result.Last(2);
            var hmaOld = _hma.Result.Last(3);

            // Sell Condition
            if (hmaPrevious > hmaCurrent && hmaPrevious > hmaOld)
            {
                ClosePositions(TradeType.Buy);
                var position = Positions.Find(Label, SymbolName, TradeType.Sell);
                if (position == null)
                {
                    var volumeInUnits = Symbol.VolumeForProportionalRisk(ProportionalAmountType.Equity, RiskPercentage, StopLossPips);
                    var normalizedVolume = Symbol.NormalizeVolumeInUnits(volumeInUnits, RoundingMode.ToNearest);
                    
                    if (normalizedVolume > 0)
                    {
                        ExecuteMarketOrder(TradeType.Sell, SymbolName, normalizedVolume, Label, StopLossPips, null);
                    }
                }
            }

            // Buy Condition
            if (hmaPrevious < hmaCurrent && hmaPrevious < hmaOld)
            {
                ClosePositions(TradeType.Sell);
                var position = Positions.Find(Label, SymbolName, TradeType.Buy);
                if (position == null)
                {
                    var volumeInUnits = Symbol.VolumeForProportionalRisk(ProportionalAmountType.Equity, RiskPercentage, StopLossPips);
                    var normalizedVolume = Symbol.NormalizeVolumeInUnits(volumeInUnits, RoundingMode.ToNearest);
                    
                    if (normalizedVolume > 0)
                    {
                        ExecuteMarketOrder(TradeType.Buy, SymbolName, normalizedVolume, Label, StopLossPips, null);
                    }
                }
            }

            TrailStopLoss();
        }

        private void TrailStopLoss()
        {
            foreach (var position in Positions.FindAll(Label, SymbolName))
            {
                if (position.TradeType == TradeType.Buy)
                {
                    var newStopLoss = Math.Round(_kc.Bottom.Last(1), Symbol.Digits);
                    if (position.StopLoss == null || newStopLoss > position.StopLoss)
                    {
                        // Updated ModifyPosition to include ProtectionType.Absolute.
                        ModifyPosition(position, newStopLoss, position.TakeProfit, ProtectionType.Absolute);
                    }
                }
                else if (position.TradeType == TradeType.Sell)
                {
                    var newStopLoss = Math.Round(_kc.Top.Last(1), Symbol.Digits);
                    if (position.StopLoss == null || newStopLoss < position.StopLoss)
                    {
                        // Updated ModifyPosition to include ProtectionType.Absolute.
                        ModifyPosition(position, newStopLoss, position.TakeProfit, ProtectionType.Absolute);
                    }
                }
            }
        }
        
        private void ClosePositions(TradeType tradeType)
        {
            foreach (var position in Positions.FindAll(Label, SymbolName, tradeType))
            {
                ClosePosition(position);
            }
        }
    }
}