using System.Net.Http.Json;
using System.Text.Json;
using System.Text.RegularExpressions;
using CartWise.Application.DTOs;
using CartWise.Application.Interfaces;
using Microsoft.Extensions.Logging;

namespace CartWise.Infrastructure.Integrations.OpenFoodFacts;

public partial class OpenFoodFactsProductDataProvider : IProductDataProvider
{
    private readonly HttpClient _httpClient;
    private readonly ILogger<OpenFoodFactsProductDataProvider> _logger;

    public OpenFoodFactsProductDataProvider(HttpClient httpClient, ILogger<OpenFoodFactsProductDataProvider> logger)
    {
        _httpClient = httpClient;
        _logger = logger;
    }

    public string Name => "OpenFoodFacts";

    public async Task<ProductLookupResult?> FindByBarcodeAsync(string barcode, CancellationToken cancellationToken = default)
    {
        try
        {
            var response = await _httpClient.GetFromJsonAsync<OpenFoodFactsResponse>($"api/v2/product/{barcode}.json", cancellationToken);

            if (response is null || response.Status != 1 || response.Product is null || string.IsNullOrWhiteSpace(response.Product.ProductName))
            {
                return null;
            }

            var (sizeValue, sizeUnit) = ParseQuantity(response.Product.Quantity);

            return new ProductLookupResult
            {
                Name = response.Product.ProductName,
                BrandName = response.Product.Brands?.Split(',').FirstOrDefault()?.Trim(),
                SizeValue = sizeValue,
                SizeUnit = sizeUnit,
                ImageUrl = response.Product.ImageUrl,
                SourceExternalId = response.Product.Code ?? barcode
            };
        }
        catch (Exception ex) when (ex is HttpRequestException or JsonException or TaskCanceledException)
        {
            LogLookupFailed(_logger, ex, barcode);
            return null;
        }
    }

    [LoggerMessage(Level = LogLevel.Warning, Message = "Open Food Facts lookup failed for barcode {Barcode}")]
    private static partial void LogLookupFailed(ILogger logger, Exception exception, string barcode);

    public Task<IReadOnlyList<ProductSearchResult>> SearchAsync(string query, CancellationToken cancellationToken = default)
    {
        // Open Food Facts text search isn't wired up for MVP; barcode lookup is the primary flow.
        return Task.FromResult<IReadOnlyList<ProductSearchResult>>([]);
    }

    private static (decimal? Value, string? Unit) ParseQuantity(string? quantity)
    {
        if (string.IsNullOrWhiteSpace(quantity))
        {
            return (null, null);
        }

        var match = QuantityPattern().Match(quantity);
        if (!match.Success || !decimal.TryParse(match.Groups["value"].Value, out var value))
        {
            return (null, null);
        }

        return (value, match.Groups["unit"].Value.Trim());
    }

    [GeneratedRegex(@"^\s*(?<value>\d+(\.\d+)?)\s*(?<unit>[a-zA-Z]+)")]
    private static partial Regex QuantityPattern();
}
