using System.Net;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
using SIGCM2.TestSupport;

namespace SIGCM2.Api.Tests.Products;

/// <summary>
/// PRD-002 Batch 8 — Guard proof: verifies that deactivating a ProductType with active Products
/// returns HTTP 409 Conflict. This test closes the W1 (dormant guard) issue from PRD-001:
/// - PRD-001: NullProductQueryRepository always returned false → guard never fired
/// - PRD-002: ProductQueryRepository now queries dbo.Product → guard fires correctly
/// </summary>
[Collection("ApiIntegration")]
public sealed class ProductTypeDeactivationGuardTests : IAsyncLifetime
{
    private const string AdminUsername = "admin";
    private const string AdminPassword = "@Diego550@";

    private readonly HttpClient _client;

    public ProductTypeDeactivationGuardTests(TestWebAppFactory factory)
    {
        _client = factory.CreateClient();
    }

    public Task InitializeAsync() => Task.CompletedTask;
    public Task DisposeAsync() => Task.CompletedTask;

    private async Task<string> GetAdminTokenAsync()
    {
        var response = await _client.PostAsJsonAsync("/api/v1/auth/login", new
        {
            username = AdminUsername,
            password = AdminPassword
        });
        response.EnsureSuccessStatusCode();
        var json = await response.Content.ReadFromJsonAsync<JsonElement>();
        return json.GetProperty("accessToken").GetString()!;
    }

    private HttpRequestMessage BuildRequest(HttpMethod method, string url, object? body = null, string? bearerToken = null)
    {
        var request = new HttpRequestMessage(method, url);
        if (bearerToken is not null)
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);
        if (body is not null)
            request.Content = JsonContent.Create(body);
        return request;
    }

    /// <summary>
    /// E2E proof: seed Medio + ProductType + active Product → DELETE product-type → expect 409.
    /// This verifies the IProductQueryRepository guard fires against real data in dbo.Product.
    /// </summary>
    [Fact]
    public async Task DeactivateProductType_WithActiveProducts_Returns409Conflict()
    {
        var token = await GetAdminTokenAsync();

        // 1. Create a Medio
        var medioResp = await _client.SendAsync(BuildRequest(HttpMethod.Post, "/api/v1/admin/medios", new
        {
            codigo = $"GD{Guid.NewGuid():N}"[..6],
            nombre = $"Guarda Medio {Guid.NewGuid():N}"[..30],
            tipo = 1
        }, token));
        medioResp.EnsureSuccessStatusCode();
        var medioJson = await medioResp.Content.ReadFromJsonAsync<JsonElement>();
        var medioId = medioJson.GetProperty("id").GetInt32();

        // 2. Create a ProductType
        var ptResp = await _client.SendAsync(BuildRequest(HttpMethod.Post, "/api/v1/admin/product-types", new
        {
            nombre = $"Guardado PT {Guid.NewGuid():N}"[..30],
            hasDuration = false, requiresText = false, requiresCategory = false, isBundle = false,
            allowImages = false
        }, token));
        ptResp.EnsureSuccessStatusCode();
        var ptJson = await ptResp.Content.ReadFromJsonAsync<JsonElement>();
        var productTypeId = ptJson.GetProperty("id").GetInt32();

        // 3. Create an active Product for this ProductType
        var prodResp = await _client.SendAsync(BuildRequest(HttpMethod.Post, "/api/v1/admin/products", new
        {
            nombre = $"Prod Guarda {Guid.NewGuid():N}"[..28],
            medioId,
            productTypeId,
            basePrice = 100m
        }, token));
        prodResp.EnsureSuccessStatusCode();

        // 4. Attempt to deactivate the ProductType — should be blocked by guard
        using var deactivateReq = BuildRequest(HttpMethod.Delete, $"/api/v1/admin/product-types/{productTypeId}", bearerToken: token);
        var deactivateResp = await _client.SendAsync(deactivateReq);

        // CRITICAL ASSERTION: 409 Conflict — guard fires because Product is active
        Assert.Equal(HttpStatusCode.Conflict, deactivateResp.StatusCode);

        var body = await deactivateResp.Content.ReadFromJsonAsync<JsonElement>();
        Assert.Equal("product_type_en_uso", body.GetProperty("error").GetString());
    }

    /// <summary>
    /// Verify guard does NOT block deactivation when Products exist but are all inactive.
    /// </summary>
    [Fact]
    public async Task DeactivateProductType_WithOnlyInactiveProducts_Returns204()
    {
        var token = await GetAdminTokenAsync();

        // 1. Create Medio
        var medioResp = await _client.SendAsync(BuildRequest(HttpMethod.Post, "/api/v1/admin/medios", new
        {
            codigo = $"GI{Guid.NewGuid():N}"[..6],
            nombre = $"Guarda Inact {Guid.NewGuid():N}"[..28],
            tipo = 1
        }, token));
        medioResp.EnsureSuccessStatusCode();
        var medioJson = await medioResp.Content.ReadFromJsonAsync<JsonElement>();
        var medioId = medioJson.GetProperty("id").GetInt32();

        // 2. Create ProductType
        var ptResp = await _client.SendAsync(BuildRequest(HttpMethod.Post, "/api/v1/admin/product-types", new
        {
            nombre = $"PT Inact {Guid.NewGuid():N}"[..28],
            hasDuration = false, requiresText = false, requiresCategory = false, isBundle = false,
            allowImages = false
        }, token));
        ptResp.EnsureSuccessStatusCode();
        var ptJson = await ptResp.Content.ReadFromJsonAsync<JsonElement>();
        var productTypeId = ptJson.GetProperty("id").GetInt32();

        // 3. Create then deactivate Product
        var prodResp = await _client.SendAsync(BuildRequest(HttpMethod.Post, "/api/v1/admin/products", new
        {
            nombre = $"Prod Inact {Guid.NewGuid():N}"[..28],
            medioId,
            productTypeId,
            basePrice = 50m
        }, token));
        prodResp.EnsureSuccessStatusCode();
        var prodJson = await prodResp.Content.ReadFromJsonAsync<JsonElement>();
        var productId = prodJson.GetProperty("id").GetInt32();

        // Deactivate the Product first
        using var deactivateProdReq = BuildRequest(HttpMethod.Delete, $"/api/v1/admin/products/{productId}", bearerToken: token);
        var deactivateProdResp = await _client.SendAsync(deactivateProdReq);
        Assert.Equal(HttpStatusCode.NoContent, deactivateProdResp.StatusCode);

        // 4. Now deactivate ProductType — should succeed since no active products
        using var deactivatePtReq = BuildRequest(HttpMethod.Delete, $"/api/v1/admin/product-types/{productTypeId}", bearerToken: token);
        var deactivatePtResp = await _client.SendAsync(deactivatePtReq);

        Assert.Equal(HttpStatusCode.NoContent, deactivatePtResp.StatusCode);
    }
}
