using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Predictalytics.Application.Interfaces;
using Predictalytics.Application.Services;
using Predictalytics.Domain.Enums;
using Predictalytics.Infrastructure.Configuration;
using Predictalytics.Infrastructure.Services;
using Xunit;

namespace Predictalytics.Application.Tests.Services;

public class EgressPoolTests
{
    [Fact]
    public void EgressPoolService_ShouldRoundRobin()
    {
        // Arrange
        var options = Options.Create(new EgressOptions
        {
            Channels = new List<EgressChannelOptions>
            {
                new() { Id = "ch-1", Type = EgressChannelType.Proxy, Value = "http://127.0.0.1:8080" },
                new() { Id = "ch-2", Type = EgressChannelType.Proxy, Value = "http://127.0.0.1:8081" },
            }
        });

        var service = new EgressPoolService(options, NullLogger<EgressPoolService>.Instance);

        // Act & Assert
        var first = service.GetNextChannelId();
        var second = service.GetNextChannelId();
        var third = service.GetNextChannelId();

        Assert.Equal("ch-1", first);
        Assert.Equal("ch-2", second);
        Assert.Equal("ch-1", third);
    }

    [Fact]
    public void EgressPoolService_ShouldFallbackToNull_WhenNoChannelsConfigured()
    {
        // Arrange
        var options = Options.Create(new EgressOptions());
        var service = new EgressPoolService(options, NullLogger<EgressPoolService>.Instance);

        // Act
        var channel = service.GetNextChannelId();

        // Assert
        Assert.Null(channel);
    }

    [Fact]
    public void EgressPoolService_ShouldCooldown_OnFailures()
    {
        // Arrange
        var options = Options.Create(new EgressOptions
        {
            Channels = new List<EgressChannelOptions>
            {
                new() { Id = "ch-1", Type = EgressChannelType.Proxy, Value = "http://127.0.0.1:8080" },
                new() { Id = "ch-2", Type = EgressChannelType.Proxy, Value = "http://127.0.0.1:8081" },
            }
        });

        var service = new EgressPoolService(options, NullLogger<EgressPoolService>.Instance);

        // Fail ch-1 three times
        service.ReportFailure("ch-1", new Exception("Fail 1"));
        service.ReportFailure("ch-1", new Exception("Fail 2"));
        service.ReportFailure("ch-1", new Exception("Fail 3"));

        // Act
        // ch-1 is in cooldown, so it should only return ch-2
        var first = service.GetNextChannelId();
        var second = service.GetNextChannelId();

        // Assert
        Assert.Equal("ch-2", first);
        Assert.Equal("ch-2", second);
    }

    [Fact]
    public async Task RateLimiterService_ShouldLimitPerChannel()
    {
        // Arrange
        var limiter = new RateLimiterService();

        // Act
        // Set a block penalty for ch-1
        limiter.ReportRateLimitExceeded(PlatformType.Polymarket, TimeSpan.FromSeconds(5), "Data", "ch-1");

        // Assert
        // ch-1 should be limited
        var canRequestCh1 = limiter.CanMakeRequest(PlatformType.Polymarket, "Data", "ch-1");
        // ch-2 should NOT be limited
        var canRequestCh2 = limiter.CanMakeRequest(PlatformType.Polymarket, "Data", "ch-2");
        // Global/Default channel should NOT be limited
        var canRequestGlobal = limiter.CanMakeRequest(PlatformType.Polymarket, "Data");

        Assert.False(canRequestCh1);
        Assert.True(canRequestCh2);
        Assert.True(canRequestGlobal);
    }
}
