using System.Net;
using System.Net.Http.Json;
using CashLineERP.Contracts.Inventory;

namespace CashLineERP.Api.Tests;

public sealed class InventoryTraceabilityQaTests : IClassFixture<ApiTestFactory>
{
    private readonly HttpClient _client;

    public InventoryTraceabilityQaTests(ApiTestFactory factory)
    {
        _client = factory.CreateClient();
    }

    [Fact]
    public async Task Inventory_Traceability_Endpoints_Return_Lot_And_Serial_History_And_Block_Invalid_Serial_Quantity()
    {
        await _client.AuthenticateAsInternalAsync();

        var invalidAdjustmentResponse = await _client.PostAsJsonAsync("/api/v1/inventory/adjustments", new CreateInventoryAdjustmentRequest(
            BranchId: 1,
            WarehouseId: 1,
            AdjustmentDate: new DateOnly(2026, 5, 27),
            ReasonCode: "TRACEABILITY",
            Notes: "Invalid serial quantity.",
            Lines:
            [
                new CreateInventoryAdjustmentLineRequest(1001, 101, 2m, "EA", 22m, "AVAILABLE", null, "HTTP-SERIAL-ERR-001", "Invalid serial")
            ]));

        Assert.Equal(HttpStatusCode.BadRequest, invalidAdjustmentResponse.StatusCode);

        var adjustmentCreateResponse = await _client.PostAsJsonAsync("/api/v1/inventory/adjustments", new CreateInventoryAdjustmentRequest(
            BranchId: 1,
            WarehouseId: 1,
            AdjustmentDate: new DateOnly(2026, 5, 28),
            ReasonCode: "TRACEABILITY",
            Notes: "Traceability inventory gain.",
            Lines:
            [
                new CreateInventoryAdjustmentLineRequest(1001, 101, 1m, "EA", 22m, "AVAILABLE", "HTTP-LOT-TRACE-001", "HTTP-SERIAL-TRACE-001", "Initial serial lot gain")
            ]));

        Assert.True(adjustmentCreateResponse.IsSuccessStatusCode, await adjustmentCreateResponse.Content.ReadAsStringAsync());
        var createdAdjustment = await adjustmentCreateResponse.Content.ReadFromJsonAsync<InventoryAdjustmentResponse>();
        Assert.NotNull(createdAdjustment);

        var submitAdjustmentResponse = await _client.PostAsync($"/api/v1/inventory/adjustments/{createdAdjustment!.InventoryAdjustmentId}/submit", null);
        Assert.True(submitAdjustmentResponse.IsSuccessStatusCode, await submitAdjustmentResponse.Content.ReadAsStringAsync());

        await _client.AuthenticateAsFinanceCheckerAsync();

        var approveAdjustmentResponse = await _client.PostAsync($"/api/v1/inventory/adjustments/{createdAdjustment.InventoryAdjustmentId}/approve", null);
        Assert.True(approveAdjustmentResponse.IsSuccessStatusCode, await approveAdjustmentResponse.Content.ReadAsStringAsync());

        var postAdjustmentResponse = await _client.PostAsync($"/api/v1/inventory/adjustments/{createdAdjustment.InventoryAdjustmentId}/post", null);
        Assert.True(postAdjustmentResponse.IsSuccessStatusCode, await postAdjustmentResponse.Content.ReadAsStringAsync());

        await _client.AuthenticateAsInternalAsync();

        var createTransferResponse = await _client.PostAsJsonAsync("/api/v1/inventory/transfers", new CreateWarehouseTransferRequest(
            BranchId: 1,
            FromWarehouseId: 1,
            ToWarehouseId: 2,
            TransferDate: new DateOnly(2026, 5, 29),
            ReasonCode: "TRACEABILITY",
            Notes: "Traceability warehouse move.",
            Lines:
            [
                new CreateWarehouseTransferLineRequest(1001, 101, 201, 1m, "EA", 22m, "AVAILABLE", "HTTP-LOT-TRACE-001", "HTTP-SERIAL-TRACE-001", "Serial relocation")
            ]));

        Assert.True(createTransferResponse.IsSuccessStatusCode, await createTransferResponse.Content.ReadAsStringAsync());
        var createdTransfer = await createTransferResponse.Content.ReadFromJsonAsync<WarehouseTransferResponse>();
        Assert.NotNull(createdTransfer);

        var submitTransferResponse = await _client.PostAsync($"/api/v1/inventory/transfers/{createdTransfer!.WarehouseTransferId}/submit", null);
        Assert.True(submitTransferResponse.IsSuccessStatusCode, await submitTransferResponse.Content.ReadAsStringAsync());

        await _client.AuthenticateAsFinanceCheckerAsync();

        var approveTransferResponse = await _client.PostAsync($"/api/v1/inventory/transfers/{createdTransfer.WarehouseTransferId}/approve", null);
        Assert.True(approveTransferResponse.IsSuccessStatusCode, await approveTransferResponse.Content.ReadAsStringAsync());

        var postTransferResponse = await _client.PostAsync($"/api/v1/inventory/transfers/{createdTransfer.WarehouseTransferId}/post", null);
        Assert.True(postTransferResponse.IsSuccessStatusCode, await postTransferResponse.Content.ReadAsStringAsync());

        var lotTraceabilityResponse = await _client.GetAsync("/api/v1/inventory/traceability/lots/HTTP-LOT-TRACE-001");
        Assert.True(lotTraceabilityResponse.IsSuccessStatusCode, await lotTraceabilityResponse.Content.ReadAsStringAsync());
        var lotTraceability = await lotTraceabilityResponse.Content.ReadFromJsonAsync<InventoryTraceabilityResponse>();
        Assert.NotNull(lotTraceability);
        Assert.Equal("LOT", lotTraceability!.TrackingType);
        Assert.Equal(1m, lotTraceability.NetTrackedQuantity);
        Assert.Contains(lotTraceability.Movements, movement => movement.BatchNumber == "HTTP-LOT-TRACE-001");

        var serialTraceabilityResponse = await _client.GetAsync("/api/v1/inventory/traceability/serials/HTTP-SERIAL-TRACE-001");
        Assert.True(serialTraceabilityResponse.IsSuccessStatusCode, await serialTraceabilityResponse.Content.ReadAsStringAsync());
        var serialTraceability = await serialTraceabilityResponse.Content.ReadFromJsonAsync<InventoryTraceabilityResponse>();
        Assert.NotNull(serialTraceability);
        Assert.Equal("SERIAL", serialTraceability!.TrackingType);
        Assert.False(serialTraceability.HasLocationConflict);
        Assert.Single(serialTraceability.Positions);
        Assert.Equal(2, serialTraceability.Positions.Single().WarehouseId);
        Assert.Equal(1m, serialTraceability.Positions.Single().NetQuantity);
        Assert.All(serialTraceability.Movements, movement => Assert.Equal("HTTP-SERIAL-TRACE-001", movement.SerialNumber));
    }
}
