using System.Net;
using CartWise.Infrastructure.Integrations.OpenFoodFacts;
using Microsoft.Extensions.Logging.Abstractions;

namespace CartWise.Application.Tests;

public class OpenFoodFactsProductDataProviderTests
{
    [Fact]
    public async Task FindByBarcodeAsync_ReturnsMappedResultWhenFound()
    {
        const string json = """
            {
              "status": 1,
              "product": {
                "product_name": "Peanut Butter",
                "brands": "Jif, Some Co-Brand",
                "quantity": "16 oz",
                "image_url": "https://example.com/image.jpg",
                "code": "051500255516"
              }
            }
            """;
        var provider = CreateProvider(HttpStatusCode.OK, json);

        var result = await provider.FindByBarcodeAsync("051500255516");

        Assert.NotNull(result);
        Assert.Equal("Peanut Butter", result!.Name);
        Assert.Equal("Jif", result.BrandName);
        Assert.Equal(16m, result.SizeValue);
        Assert.Equal("oz", result.SizeUnit);
        Assert.Equal("051500255516", result.SourceExternalId);
    }

    [Fact]
    public async Task FindByBarcodeAsync_ReturnsNullWhenStatusIsNotFound()
    {
        const string json = """{ "status": 0 }""";
        var provider = CreateProvider(HttpStatusCode.OK, json);

        var result = await provider.FindByBarcodeAsync("000000000000");

        Assert.Null(result);
    }

    [Fact]
    public async Task FindByBarcodeAsync_ReturnsNullOnHttpFailure()
    {
        var provider = CreateProvider(HttpStatusCode.InternalServerError, "error");

        var result = await provider.FindByBarcodeAsync("051500255516");

        Assert.Null(result);
    }

    [Fact]
    public async Task FindByBarcodeAsync_ReturnsNullOnMalformedJson()
    {
        var provider = CreateProvider(HttpStatusCode.OK, "{not valid json");

        var result = await provider.FindByBarcodeAsync("051500255516");

        Assert.Null(result);
    }

    private static OpenFoodFactsProductDataProvider CreateProvider(HttpStatusCode statusCode, string content)
    {
        var handler = new FakeHttpMessageHandler(statusCode, content);
        var httpClient = new HttpClient(handler) { BaseAddress = new Uri("https://off.example.com/") };
        return new OpenFoodFactsProductDataProvider(httpClient, NullLogger<OpenFoodFactsProductDataProvider>.Instance);
    }

    private sealed class FakeHttpMessageHandler : HttpMessageHandler
    {
        private readonly HttpStatusCode _statusCode;
        private readonly string _content;

        public FakeHttpMessageHandler(HttpStatusCode statusCode, string content)
        {
            _statusCode = statusCode;
            _content = content;
        }

        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var response = new HttpResponseMessage(_statusCode)
            {
                Content = new StringContent(_content)
            };
            return Task.FromResult(response);
        }
    }
}
