using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Robots
{
    public enum TradingDirection
    {
        Both,
        LongOnly,
        ShortOnly
    }

    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class MultiSmaHmaNotify : Robot
    {
        #region Parameters

        [Parameter("SMA Period", DefaultValue = 200, MinValue = 1)]
        public int SmaPeriod { get; set; }

        [Parameter("HMA Period", DefaultValue = 250, MinValue = 1)]
        public int HmaPeriod { get; set; }

        [Parameter("Trading Direction", DefaultValue = TradingDirection.Both)]
        public TradingDirection AllowedDirection { get; set; }

        [Parameter("Sound File Path", DefaultValue = @"C:\Windows\Media\Alarm05.wav")]
        public string SoundFilePath { get; set; }

        [Parameter("Telegram Bot Token", DefaultValue = "8569913524:AAE9RGsvkBPa0yhTFCKBjVeST0fuzdOx5w0")]
        public string TelegramBotToken { get; set; }

        [Parameter("Telegram Chat ID", DefaultValue = "5171721381")]
        public string TelegramChatId { get; set; }

        [Parameter("Symbols (CSV)", DefaultValue = "", Group = "Multi Symbol")]
        public string SymbolsCsv { get; set; }

        #endregion

        #region Fields

        private HttpClient _httpClient;
        private List<SymbolMonitor> _monitors;

        #endregion

        protected override void OnStart()
        {
            _httpClient = new HttpClient();
            _monitors = new List<SymbolMonitor>();

            // Parse Symbols
            var symbolNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

            if (!string.IsNullOrWhiteSpace(SymbolsCsv))
            {
                var split = SymbolsCsv.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var s in split)
                {
                    symbolNames.Add(s.Trim());
                }
            }
            else
            {
                // Fallback: Use current symbol if list is empty
                symbolNames.Add(SymbolName);
            }

            foreach (var name in symbolNames)
            {
                InitializeSymbolMonitor(name);
            }
        }

        private void InitializeSymbolMonitor(string symbolName)
        {
            Symbol symbol = Symbols.GetSymbol(symbolName);
            if (symbol == null)
            {
                Print($"Error: Symbol '{symbolName}' not found.");
                return;
            }

            // Get Bars for the requested symbol and timeframe matches the instance timeframe
            Bars bars = MarketData.GetBars(TimeFrame, symbolName);

            // Create Context
            var monitor = new SymbolMonitor(this, symbol, bars);
            _monitors.Add(monitor);

            // Subscribe to BarOpened event (triggers when a bar closes and a new one opens)
            bars.BarOpened += (args) => monitor.OnBarOpened();
            
            // Load enough history to calculate indicators immediately
            int maxPeriod = Math.Max(SmaPeriod, HmaPeriod);
            if (bars.Count < maxPeriod) 
            {
                bars.LoadMoreHistory();
            }
        }

        protected override void OnStop()
        {
            _httpClient?.Dispose();
        }
        
        // Expose helper methods for the inner class
        public void Log(string message) => Print(message);
        
        public void PlaySound()
        {
            try
            {
                if (!string.IsNullOrWhiteSpace(SoundFilePath))
                {
                    Notifications.PlaySound(SoundFilePath);
                }
            }
            catch (Exception ex)
            {
                Print("Error playing sound: {0}", ex.Message);
            }
        }

        public void SendTelegram(string message)
        {
             Task.Run(() => SendTelegramMessageAsync(message));
        }

        private async Task SendTelegramMessageAsync(string message)
        {
            if (string.IsNullOrWhiteSpace(TelegramBotToken) || string.IsNullOrWhiteSpace(TelegramChatId))
                return;

            try
            {
                string url = $"https://api.telegram.org/bot{TelegramBotToken}/sendMessage?chat_id={TelegramChatId}&text={Uri.EscapeDataString(message)}&parse_mode=HTML";
                HttpResponseMessage response = await _httpClient.GetAsync(url);
                if (!response.IsSuccessStatusCode)
                    Print("Telegram Error: {0}", response.StatusCode);
            }
            catch (Exception ex)
            {
                Print("Exception sending Telegram message: {0}", ex.Message);
            }
        }

        /// <summary>
        /// Inner class to handle state per symbol
        /// </summary>
        private class SymbolMonitor
        {
            private readonly MultiSmaHmaNotify _bot;
            private readonly Symbol _symbol;
            private readonly Bars _bars;
            private readonly SimpleMovingAverage _sma;
            private readonly HullMovingAverage _hma;

            private bool _waitingForSmaRise;
            private bool _waitingForSmaFall;

            public SymbolMonitor(MultiSmaHmaNotify bot, Symbol symbol, Bars bars)
            {
                _bot = bot;
                _symbol = symbol;
                _bars = bars;

                // Create indicators based on the specific bars series
                _sma = _bot.Indicators.SimpleMovingAverage(_bars.ClosePrices, _bot.SmaPeriod);
                _hma = _bot.Indicators.HullMovingAverage(_bars.ClosePrices, _bot.HmaPeriod);
            }

            public void OnBarOpened()
            {
                // Ensure we have enough data
                if (_bars.Count <= Math.Max(_bot.SmaPeriod, _bot.HmaPeriod) + 1) return;

                // Index 1 is the last closed bar, Index 2 is the one before that
                double smaClosed = _sma.Result.Last(1);
                double smaPrev   = _sma.Result.Last(2);
                
                double hmaClosed = _hma.Result.Last(1);
                double hmaPrev   = _hma.Result.Last(2);

                bool isSmaRising = smaClosed > smaPrev;
                bool isSmaFalling = smaClosed < smaPrev;

                bool isCrossUp = (hmaPrev <= smaPrev) && (hmaClosed > smaClosed);
                bool isCrossDown = (hmaPrev >= smaPrev) && (hmaClosed < smaClosed);

                bool isHmaAbove = hmaClosed > smaClosed;
                bool isHmaBelow = hmaClosed < smaClosed;

                // Check Long Logic
                if (_bot.AllowedDirection == TradingDirection.Both || _bot.AllowedDirection == TradingDirection.LongOnly)
                {
                    if (isCrossUp)
                    {
                        _waitingForSmaFall = false; 

                        if (isSmaRising)
                        {
                            TriggerSignal("BUY", "SMA Rising + HMA CrossUp (Immediate)");
                            _waitingForSmaRise = false;
                        }
                        else
                        {
                            _waitingForSmaRise = true;
                        }
                    }
                    else if (_waitingForSmaRise)
                    {
                        if (!isHmaAbove)
                        {
                            _waitingForSmaRise = false; // Invalidated
                        }
                        else if (isSmaRising)
                        {
                            TriggerSignal("BUY", "SMA Started Rising after HMA CrossUp (Delayed)");
                            _waitingForSmaRise = false;
                        }
                    }
                }
                else
                {
                    _waitingForSmaRise = false;
                }

                // Check Short Logic
                if (_bot.AllowedDirection == TradingDirection.Both || _bot.AllowedDirection == TradingDirection.ShortOnly)
                {
                    if (isCrossDown)
                    {
                        _waitingForSmaRise = false;

                        if (isSmaFalling)
                        {
                            TriggerSignal("SELL", "SMA Falling + HMA CrossDown (Immediate)");
                            _waitingForSmaFall = false;
                        }
                        else
                        {
                            _waitingForSmaFall = true;
                        }
                    }
                    else if (_waitingForSmaFall)
                    {
                        if (!isHmaBelow)
                        {
                            _waitingForSmaFall = false; // Invalidated
                        }
                        else if (isSmaFalling)
                        {
                            TriggerSignal("SELL", "SMA Started Falling after HMA CrossDown (Delayed)");
                            _waitingForSmaFall = false;
                        }
                    }
                }
                else
                {
                    _waitingForSmaFall = false;
                }
            }

            private void TriggerSignal(string type, string reason)
            {
                // Convert Time
                string localTime = TimeZoneInfo.ConvertTimeFromUtc(_bot.TimeInUtc, _bot.TimeZone).ToString("yyyy-MM-dd HH:mm:ss");
                
                // Drawing only if this is the chart symbol
                if (_symbol.Name == _bot.SymbolName)
                {
                    int index = _bars.Count - 2; // Last closed bar
                    if (type == "BUY")
                        _bot.Chart.DrawIcon("BuySignal_" + index, ChartIconType.UpArrow, index, _bars.LowPrices[index] - _symbol.PipSize * 5, Color.Green);
                    else if (type == "SELL")
                        _bot.Chart.DrawIcon("SellSignal_" + index, ChartIconType.DownArrow, index, _bars.HighPrices[index] + _symbol.PipSize * 5, Color.Red);
                }

                string logMessage = $"[{localTime}] {_symbol.Name} ({_bot.TimeFrame}) {type}: {reason}";
                _bot.Log(logMessage);

                if (!_bot.IsBacktesting)
                {
                    _bot.PlaySound();
                    
                    string emoji = (type == "BUY" ? "🟢" : (type == "SELL" ? "🔴" : "ℹ"));
                    string htmlMessage = $"{emoji} <b>{_symbol.Name}</b> ({_bot.TimeFrame})\n" +
                                         $"<b>{type} Signal</b>\n" +
                                         $"Reason: <i>{reason}</i>\n" +
                                         $"Time: <code>{localTime}</code>";
                    
                    _bot.SendTelegram(htmlMessage);
                }
            }
        }
    }
}