using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using Predictalytics.Application.Interfaces;
using Predictalytics.Domain.Entities;
using Predictalytics.Domain.Enums;
using Predictalytics.Infrastructure.Data;
using Predictalytics.Infrastructure.Providers.Polymarket;
using Predictalytics.Infrastructure.Services;
using Xunit;

namespace Predictalytics.Application.Tests.Services;

public class BackendRedesignTests
{
    [Fact]
    public async Task AppDbContext_ShouldThrow_WhenReadOnlyDatabaseTrue()
    {
        // Arrange
        var inMemorySettings = new Dictionary<string, string?> {
            {"ApiSettings:ReadOnlyDatabase", "true"}
        };
        var configuration = new ConfigurationBuilder()
            .AddInMemoryCollection(inMemorySettings)
            .Build();

        var options = new DbContextOptionsBuilder<AppDbContext>()
            .UseInMemoryDatabase(databaseName: "ReadOnlyTestDb")
            .Options;

        using var db = new AppDbContext(options, configuration);

        db.Traders.Add(new Trader
        {
            Id = 1,
            Platform = PlatformType.Polymarket,
            PlatformUserId = "0x123",
            DisplayName = "Test"
        });

        // Act & Assert
        await Assert.ThrowsAsync<InvalidOperationException>(async () => await db.SaveChangesAsync());
    }

    [Fact]
    public async Task PolymarketApiClient_ShouldUseCache_ForGetMarketAsync()
    {
        // Arrange
        var services = new ServiceCollection();
        services.AddMemoryCache();
        var serviceProvider = services.BuildServiceProvider();
        var cache = serviceProvider.GetRequiredService<IMemoryCache>();

        // Set up mock HTTP handler returning a list containing a GammaMarketResponse
        var mockResponse = new List<GammaMarketResponse>
        {
            new() { ConditionId = "cond-1", Question = "Will it rain?" }
        };

        var handlerCallCount = 0;
        var mockHandler = new MockHttpMessageHandler(req =>
        {
            handlerCallCount++;
            var response = new HttpResponseMessage(HttpStatusCode.OK);
            response.Content = JsonContent.Create(mockResponse);
            return response;
        });

        var httpClient = new HttpClient(mockHandler);
        var httpFactoryMock = new MockHttpClientFactory(httpClient);

        var rateLimiterMock = new MockRateLimiter();
        var egressPoolMock = new MockEgressPoolService();

        var client = new PolymarketApiClient(
            httpFactoryMock,
            rateLimiterMock,
            egressPoolMock,
            cache,
            NullLogger<PolymarketApiClient>.Instance
        );

        // Act
        // 1. First fetch: should trigger HTTP handler
        var m1 = await client.GetMarketAsync("cond-1");

        // 2. Second fetch: should serve from cache
        var m2 = await client.GetMarketAsync("cond-1");

        // Assert
        Assert.NotNull(m1);
        Assert.Equal("cond-1", m1.ConditionId);
        Assert.Equal("cond-1", m2?.ConditionId);
        Assert.Equal(1, handlerCallCount); // Only 1 HTTP call made
    }

    private class MockHttpClientFactory : IHttpClientFactory
    {
        private readonly HttpClient _client;
        public MockHttpClientFactory(HttpClient client) => _client = client;
        public HttpClient CreateClient(string name) => _client;
    }

    private class MockRateLimiter : IRateLimiter
    {
        public Task WaitAsync(PlatformType platform, CancellationToken ct = default, string endpointGroup = "Default", string? channelId = null) => Task.CompletedTask;
        public bool CanMakeRequest(PlatformType platform, string endpointGroup = "Default", string? channelId = null) => true;
        public void ReportRateLimitExceeded(PlatformType platform, TimeSpan? retryAfter = null, string endpointGroup = "Default", string? channelId = null) { }
    }

    private class MockEgressPoolService : IEgressPoolService
    {
        public string? GetNextChannelId() => null;
        public HttpMessageInvoker? GetInvoker(string channelId) => null;
        public void ReportFailure(string channelId, Exception exception) { }
        public void ReportSuccess(string channelId) { }
    }

    private class MockHttpMessageHandler : HttpMessageHandler
    {
        private readonly Func<HttpRequestMessage, HttpResponseMessage> _sender;

        public MockHttpMessageHandler(Func<HttpRequestMessage, HttpResponseMessage> sender)
        {
            _sender = sender;
        }

        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            return Task.FromResult(_sender(request));
        }
    }
}
