using System.Net.Http.Json;
using System.Text.Json;
using FluentAssertions;
using foodmarket.IntegrationTests.Support;
using Xunit;

namespace foodmarket.IntegrationTests;

[Collection(ApiCollection.Name)]
public class SupplyPostUnpostTests
{
    private readonly ApiFactory _factory;
    public SupplyPostUnpostTests(ApiFactory factory) => _factory = factory;

    private static string RandomBarcode()
        => string.Concat(Enumerable.Range(0, 13).Select(_ => Random.Shared.Next(0, 10)));

    [Fact]
    public async Task Posting_supply_raises_stock_and_sets_cost_unpost_reverts()
    {
        var api = new ApiActor(_factory.CreateClient());
        await api.SignupAndLoginAsync($"supply-{Guid.NewGuid():N}");
        var refs = await api.LoadRefsAsync();
        var supplierId = await api.CreateCounterpartyAsync($"Supplier-{Guid.NewGuid():N}");
        var productId = await api.CreateProductAsync(refs, $"Prod-{Guid.NewGuid():N}", retailPrice: 150m, RandomBarcode());

        (await api.StockOfAsync(refs.StoreId, productId)).Should().Be(0m, "новый товар без приёмок");

        // Draft supply: 10 шт по 70.
        var draftResp = await api.Http.PostAsJsonAsync("/api/purchases/supplies", new
        {
            date = DateTime.UtcNow,
            supplierId,
            storeId = refs.StoreId,
            currencyId = refs.CurrencyId,
            notes = "integration",
            lines = new[] { new { productId, quantity = 10m, unitPrice = 70m } },
        });
        draftResp.EnsureSuccessStatusCode();
        var supplyId = (await draftResp.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("id").GetString();

        // Post → остаток 10, себестоимость 70 (скользящее среднее с нуля).
        using var post = await api.Http.PostAsJsonAsync($"/api/purchases/supplies/{supplyId}/post", new { });
        post.IsSuccessStatusCode.Should().BeTrue($"post вернул {(int)post.StatusCode}: {await post.Content.ReadAsStringAsync()}");

        (await api.StockOfAsync(refs.StoreId, productId)).Should().Be(10m);
        var product = await api.GetJsonAsync($"/api/catalog/products/{productId}");
        product.GetProperty("cost").GetDecimal().Should().Be(70m);

        // Unpost → остаток возвращается к 0.
        using var unpost = await api.Http.PostAsJsonAsync($"/api/purchases/supplies/{supplyId}/unpost", new { });
        unpost.IsSuccessStatusCode.Should().BeTrue($"unpost вернул {(int)unpost.StatusCode}: {await unpost.Content.ReadAsStringAsync()}");

        (await api.StockOfAsync(refs.StoreId, productId)).Should().Be(0m);
    }

    [Fact]
    public async Task Double_post_is_rejected()
    {
        var api = new ApiActor(_factory.CreateClient());
        await api.SignupAndLoginAsync($"dblpost-{Guid.NewGuid():N}");
        var refs = await api.LoadRefsAsync();
        var supplierId = await api.CreateCounterpartyAsync($"Supplier-{Guid.NewGuid():N}");
        var productId = await api.CreateProductAsync(refs, $"Prod-{Guid.NewGuid():N}", 150m, RandomBarcode());

        var draftResp = await api.Http.PostAsJsonAsync("/api/purchases/supplies", new
        {
            date = DateTime.UtcNow, supplierId, storeId = refs.StoreId, currencyId = refs.CurrencyId,
            notes = "dbl", lines = new[] { new { productId, quantity = 3m, unitPrice = 50m } },
        });
        draftResp.EnsureSuccessStatusCode();
        var supplyId = (await draftResp.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("id").GetString();

        (await api.Http.PostAsJsonAsync($"/api/purchases/supplies/{supplyId}/post", new { }))
            .IsSuccessStatusCode.Should().BeTrue();
        using var second = await api.Http.PostAsJsonAsync($"/api/purchases/supplies/{supplyId}/post", new { });
        ((int)second.StatusCode).Should().Be(409);
    }
}
