using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using PolyTrader.Core.Streaming;
using PolyTrader.Modules.CopyTrading.Logic;
using PolyTraderSharp.Models;

namespace PolyTraderSharp.Services
{
    public class AlchemyWebsocketService : BackgroundService
    {
        private readonly TradingState _state;
        private readonly CopyTradingState _copyState;
        private readonly ServerSettings _settings;
        private readonly TraderMonitorService _traderMonitor;
        private readonly TerminalLogger _logger;
        private readonly IBlockchainWssClientFactory _wssFactory;

        public AlchemyWebsocketService(
            TradingState state,
            CopyTradingState copyState,
            ServerSettings settings,
            TraderMonitorService traderMonitor,
            TerminalLogger logger,
            IBlockchainWssClientFactory wssFactory)
        {
            _state = state;
            _copyState = copyState;
            _settings = settings;
            _traderMonitor = traderMonitor;
            _logger = logger;
            _wssFactory = wssFactory;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            if (!_settings.EnableBlockchainListener || string.IsNullOrEmpty(_settings.PolygonRpcUrl))
            {
                _logger.Info("Blockchain Listener is disabled in settings. Using raw polling.");
                _state.IsAlchemyHealthy = false;
                return;
            }

            _logger.Info("Alchemy WSS Service starting up...");

            while (!stoppingToken.IsCancellationRequested)
            {
                if (_state.GlobalTradingPaused ||
                   (_state.LiveTradingMode == TradingMode.Inactive && _state.DemoTradingMode == TradingMode.Inactive))
                {
                    _state.IsAlchemyHealthy = false;
                    await Task.Delay(5000, stoppingToken);
                    continue;
                }

                try
                {
                    await ConnectAndListenAsync(stoppingToken);
                }
                catch (WebSocketException ex)
                {
                    // Usually indicates a connection drop or 429
                    _logger.Warning($"Alchemy WSS drop: {ex.Message}. Falling back to API polling for 5 minutes.");
                    _state.IsAlchemyHealthy = false;
                    await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
                }
                catch (Exception ex)
                {
                    if (ex.Message.Contains("429") || ex.Message.Contains("Too Many Requests"))
                    {
                        _logger.Error($"Alchemy HTTP 429 Limit reached. Suspending WSS for 5 minutes.");
                        _state.IsAlchemyHealthy = false;
                        await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
                    }
                    else
                    {
                        _logger.Error($"Alchemy WSS Error: {ex.Message}. Retrying in 10s...");
                        _state.IsAlchemyHealthy = false;
                        await Task.Delay(10000, stoppingToken);
                    }
                }
            }
        }

        /// <summary>
        /// Baut EINE WSS-Session über den Core-Client auf. Consumer-Verantwortung: Filter aus den
        /// getrackten Master-Tradern bauen, auf Trader-Listen-Änderungen re-subscriben, Health spiegeln.
        /// </summary>
        private async Task ConnectAndListenAsync(CancellationToken stoppingToken)
        {
            var activeTraders = _copyState.Traders.Values.Where(t => t.IsActive).ToList();
            var activeStateHash = string.Join(",", activeTraders.OrderBy(t => t.Id).Select(t => t.WalletAddress.ToLowerInvariant()));

            var subscription = BlockchainSubscription.Build(activeTraders);
            if (subscription.Filters.Count == 0)
            {
                _logger.Info("Keine aktiven Master-Trader. Socket läuft im Standby...");
                _state.IsAlchemyHealthy = false;
                await Task.Delay(5000, stoppingToken);
                return;
            }

            var client = _wssFactory.Create();
            _logger.Info("Connecting to Alchemy WebSocket (Core WSS client)...");

            using var loopCts = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken);

            // Überwacht Trader-Listen-Änderungen (Re-Subscribe) und spiegelt das Health-Flag.
            var monitorTask = Task.Run(async () =>
            {
                while (!loopCts.IsCancellationRequested)
                {
                    try { await Task.Delay(5000, loopCts.Token); }
                    catch (OperationCanceledException) { break; }

                    _state.IsAlchemyHealthy = client.IsHealthy;

                    var currentTraders = _copyState.Traders.Values.Where(t => t.IsActive).ToList();
                    var currentHash = string.Join(",", currentTraders.OrderBy(t => t.Id).Select(t => t.WalletAddress.ToLowerInvariant()));
                    if (currentHash != activeStateHash)
                    {
                        _logger.Info("🔄 Master-Trader Liste hat sich geändert. Starte Alchemy WSS mit neuen Filtern neu...");
                        loopCts.Cancel();
                        break;
                    }
                }
            });

            try
            {
                await client.ConnectAndListenAsync(_settings.PolygonRpcUrl, subscription, OnLog, loopCts.Token);
            }
            catch (OperationCanceledException)
            {
                // Erwartet beim Re-Subscribe (Trader-Liste geändert) oder beim Shutdown.
            }
            finally
            {
                _state.IsAlchemyHealthy = false;
                if (!loopCts.IsCancellationRequested) loopCts.Cancel();
            }
        }

        private void OnLog(BlockchainLogEvent evt)
        {
            if (evt.Topics.Count < 4) return;

            var fromTopic = evt.Topics[2]?.ToLowerInvariant();
            var toTopic = evt.Topics[3]?.ToLowerInvariant();
            if (fromTopic == null || toTopic == null) return;

            var activeTraders = _copyState.Traders.Values.Where(t => t.IsActive).ToList();
            string? triggeredAddress = null;

            foreach (var trader in activeTraders)
            {
                var padded = BlockchainSubscription.PadAddress(trader.WalletAddress);
                if (fromTopic == padded || toTopic == padded)
                {
                    triggeredAddress = trader.WalletAddress;
                    break;
                }
            }

            if (!string.IsNullOrEmpty(triggeredAddress))
            {
                _traderMonitor.TriggerFastBlockchainPoll(evt.TransactionHash, _settings.PolygonRpcUrl, triggeredAddress);
            }
        }
    }
}
