using System;
using System.Linq; // Required for .Where() and .Count()
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Robots
{
    // Strategy based on two HMAs (fast and slow)
    [Robot(AccessRights = AccessRights.None, TimeZone = TimeZones.UTC)]
    public class HMACrossBot : Robot
    {
        [Parameter("Fast HMA Period", DefaultValue = 20, MinValue = 2)]
        public int FastHmaPeriod { get; set; }

        [Parameter("Slow HMA Period", DefaultValue = 25, MinValue = 2)]
        public int SlowHmaPeriod { get; set; }

        [Parameter("Max Positions (per side)", DefaultValue = 3, MinValue = 1)]
        public int MaxPositions { get; set; }

        [Parameter("Volume (Units)", DefaultValue = 0.1, MinValue = 0.1)]
        public double VolumeInUnits { get; set; }

        private HullMovingAverage _fastHma;
        private HullMovingAverage _slowHma;
        
        // A unique label to identify positions opened by this cBot instance
        private string _botLabel;

        // Initialize indicators and check parameters
        protected override void OnStart()
        {
            if (FastHmaPeriod >= SlowHmaPeriod)
            {
                Print("Error: Fast HMA Period must be less than Slow HMA Period for this logic.");
                Stop();
                return;
            }
            
            _fastHma = Indicators.HullMovingAverage(Bars.ClosePrices, FastHmaPeriod);
            _slowHma = Indicators.HullMovingAverage(Bars.ClosePrices, SlowHmaPeriod);
            
            // Generate a unique label for this cBot instance
            _botLabel = $"HMACrossBot_{SymbolName}_{TimeFrame}_{InstanceId}";
        }

        // Main logic executed at the close of each bar
        protected override void OnBar()
        {
            // Ensure we have enough data to calculate HMA direction
            if (_slowHma.Result.Count < 3)
            {
                return;
            }

            // --- 1. Get HMA values ---
            // Use index 1 (the most recently closed bar) as OnBar fires at the close.
            double fastHmaCurrent = _fastHma.Result.Last(1);
            double slowHmaCurrent = _slowHma.Result.Last(1);
            double slowHmaPrevious = _slowHma.Result.Last(2);

            // --- 2. Check Exit Conditions (Close First) ---
            
            // Close all LONG positions if fast HMA crosses below or equals slow HMA
            if (fastHmaCurrent <= slowHmaCurrent)
            {
                ClosePositions(TradeType.Buy);
            }
            
            // Close all SHORT positions if fast HMA crosses above or equals slow HMA
            // (Corrected: Use TradeType.Sell, not .Short)
            if (fastHmaCurrent >= slowHmaCurrent)
            {
                ClosePositions(TradeType.Sell);
            }

            // --- 3. Check Entry Conditions (Open After) ---
            
            // Get current positions count (check only positions managed by this bot)
            int longPositionsCount = Positions.Count(p => p.Label == _botLabel && p.SymbolName == SymbolName && p.TradeType == TradeType.Buy);
            // (Corrected: Use TradeType.Sell, not .Short)
            int shortPositionsCount = Positions.Count(p => p.Label == _botLabel && p.SymbolName == SymbolName && p.TradeType == TradeType.Sell);

            // LONG Entry: fast > slow AND slow is rising
            if ((fastHmaCurrent > slowHmaCurrent) && (slowHmaCurrent > slowHmaPrevious))
            {
                if (longPositionsCount < MaxPositions)
                {
                    ExecuteTrade(TradeType.Buy);
                }
            }

            // SHORT Entry: fast < slow AND slow is falling
            if ((fastHmaCurrent < slowHmaCurrent) && (slowHmaCurrent < slowHmaPrevious))
            {
                if (shortPositionsCount < MaxPositions)
                {
                    // (Corrected: Use TradeType.Sell, not .Short)
                    ExecuteTrade(TradeType.Sell);
                }
            }
        }

        // Helper to execute a trade with normalized volume
        private void ExecuteTrade(TradeType tradeType)
        {
            // Normalize volume to the symbol's requirements
            double volumeToTrade = Symbol.NormalizeVolumeInUnits(VolumeInUnits, RoundingMode.ToNearest);
            
            // Ensure minimum volume is met
            if (volumeToTrade < Symbol.VolumeInUnitsMin)
            {
                volumeToTrade = Symbol.VolumeInUnitsMin;
            }
            
            ExecuteMarketOrder(tradeType, SymbolName, volumeToTrade, _botLabel);
        }

        // Helper to close all positions of a specific type
        private void ClosePositions(TradeType tradeType)
        {
            // Find all positions for the specified trade type and label
            // (Corrected: Removed 'IsClosing' check, as it's not on Position interface)
            var positionsToClose = Positions
                .Where(p => p.Label == _botLabel && 
                            p.SymbolName == SymbolName && 
                            p.TradeType == tradeType)
                .ToList();
            
            foreach (var position in positionsToClose)
            {
                // Asynchronously close each position
                ClosePositionAsync(position);
            }
        }

        protected override void OnStop()
        {
            // cBot is stopping
        }

        protected override void OnTick()
        {
            // All logic is handled OnBar in this strategy
        }
    }
}