using Predictalytics.Application.Interfaces;
using Predictalytics.Domain.Enums;
using Predictalytics.Domain.Interfaces;
using Predictalytics.Infrastructure.Logging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Configuration;

namespace Predictalytics.Worker.Services;

/// <summary>
/// Background service that discovers new traders by scanning the top holders
/// of active markets. Complements the leaderboard-based discovery by finding
/// traders who hold significant positions in currently traded markets.
/// </summary>
public class TopHolderDiscoveryWorker : BackgroundService
{
    private readonly IServiceProvider _services;
    private readonly ILogger<TopHolderDiscoveryWorker> _logger;

    public TopHolderDiscoveryWorker(IServiceProvider services, ILogger<TopHolderDiscoveryWorker> logger)
    { _services = services; _logger = logger; }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("👥 TopHolderDiscoveryWorker started");
        await Task.Delay(20000, stoppingToken); // Let market sync populate markets first

        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                using var scope = _services.CreateScope();
                var marketRepo = scope.ServiceProvider.GetRequiredService<IMarketRepository>();
                var traderRepo = scope.ServiceProvider.GetRequiredService<ITraderRepository>();
                var providers = scope.ServiceProvider.GetRequiredService<IEnumerable<IPlatformProvider>>();
                var rateLimiter = scope.ServiceProvider.GetRequiredService<IRateLimiter>();

                var activeMarkets = await marketRepo.GetActiveAsync(100, stoppingToken);
                _logger.LogInformation("👥 Scanning top holders across {Count} active markets", activeMarkets.Count);

                var config = scope.ServiceProvider.GetRequiredService<Microsoft.Extensions.Configuration.IConfiguration>();
                int totalDiscovered = 0;

                foreach (var market in activeMarkets)
                {
                    if (stoppingToken.IsCancellationRequested) break;
                    
                    bool isEnabled = config.GetValue<bool>($"PlatformSettings:{market.Platform}:EnableCrawling", market.Platform == PlatformType.Polymarket);
                    if (!isEnabled) continue;

                    var provider = providers.FirstOrDefault(p => p.Platform == market.Platform && p.IsImplemented);
                    if (provider == null) continue;

                    try
                    {
                        using var platformCtx = PlatformLogContext.Push(provider.PlatformName);
                        await rateLimiter.WaitAsync(market.Platform, stoppingToken);

                        var newHolders = await provider.GetTopHoldersAsync(market.ConditionId, 50, stoppingToken);

                        foreach (var holder in newHolders)
                        {
                            // Skip empty wallet addresses
                            if (string.IsNullOrWhiteSpace(holder.PlatformUserId)) continue;

                            var existing = await traderRepo.GetByPlatformIdAsync(
                                market.Platform, holder.PlatformUserId, stoppingToken);

                            if (existing == null)
                            {
                                var trader = new Domain.Entities.Trader
                                {
                                    Platform = market.Platform,
                                    PlatformUserId = holder.PlatformUserId,
                                    DisplayName = holder.DisplayName,
                                    IsAutoDiscovered = true,
                                    CreatedAt = DateTime.UtcNow
                                };

                                await traderRepo.AddAsync(trader, stoppingToken);
                                totalDiscovered++;

                                _logger.LogInformation("[{Platform}] Discovered trader {Name} ({Wallet}) from market: {Market}",
                                    provider.PlatformName, holder.DisplayName, holder.PlatformUserId[..10] + "...",
                                    market.Question.Length > 60 ? market.Question[..60] + "..." : market.Question);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, "Error scanning holders for market {Market}", market.PlatformMarketId);
                    }
                }

                _logger.LogInformation("✅ TopHolderDiscovery complete: {Count} new traders discovered", totalDiscovered);
            }
            catch (OperationCanceledException) { break; }
            catch (Exception ex) { _logger.LogError(ex, "TopHolderDiscoveryWorker error"); }

            // Run every 5 minutes
            _logger.LogInformation("🚀 Next top holder scan in 5 minutes.");
            await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
        }

        _logger.LogInformation("👥 TopHolderDiscoveryWorker stopped");
    }
}
