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 DemandPostUnpostTests
{
    private readonly ApiFactory _factory;
    public DemandPostUnpostTests(ApiFactory factory) => _factory = factory;
    private static string RandomBarcode()
        => string.Concat(Enumerable.Range(0, 13).Select(_ => Random.Shared.Next(0, 10)));

    [Fact]
    public async Task Post_decrements_stock_unpost_restores()
    {
        var api = new ApiActor(_factory.CreateClient());
        await api.SignupAndLoginAsync($"dem-{Guid.NewGuid():N}");
        var refs = await api.LoadRefsAsync();
        var customerId = await api.CreateCounterpartyAsync($"Cust-{Guid.NewGuid():N}");
        var p1 = await api.CreateProductAsync(refs, $"P-{Guid.NewGuid():N}", 200m, RandomBarcode());

        var enter = await api.Http.PostAsJsonAsync("/api/inventory/enters", new
        {
            date = DateTime.UtcNow, storeId = refs.StoreId, currencyId = refs.CurrencyId,
            notes = "seed", lines = new[] { new { productId = p1, quantity = 20m, unitCost = 100m } },
        });
        enter.EnsureSuccessStatusCode();
        var eid = (await enter.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("id").GetString();
        (await api.Http.PostAsJsonAsync($"/api/inventory/enters/{eid}/post", new { })).EnsureSuccessStatusCode();

        var demand = await api.Http.PostAsJsonAsync("/api/sales/demands", new
        {
            date = DateTime.UtcNow, customerId, storeId = refs.StoreId, currencyId = refs.CurrencyId,
            payment = 2, // BankTransfer
            paidAmount = 0m, notes = "test demand",
            lines = new[] { new { productId = p1, quantity = 5m, unitPrice = 180m, discount = 0m, vatPercent = 12m } },
        });
        demand.EnsureSuccessStatusCode();
        var did = (await demand.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("id").GetString();

        using var post = await api.Http.PostAsJsonAsync($"/api/sales/demands/{did}/post", new { });
        post.IsSuccessStatusCode.Should().BeTrue($"post вернул {(int)post.StatusCode}: {await post.Content.ReadAsStringAsync()}");
        (await api.StockOfAsync(refs.StoreId, p1)).Should().Be(15m);

        using var unpost = await api.Http.PostAsJsonAsync($"/api/sales/demands/{did}/unpost", new { });
        unpost.IsSuccessStatusCode.Should().BeTrue();
        (await api.StockOfAsync(refs.StoreId, p1)).Should().Be(20m);
    }

    [Fact]
    public async Task Cannot_post_when_stock_insufficient()
    {
        var api = new ApiActor(_factory.CreateClient());
        await api.SignupAndLoginAsync($"dem-short-{Guid.NewGuid():N}");
        var refs = await api.LoadRefsAsync();
        var customerId = await api.CreateCounterpartyAsync($"Cust-{Guid.NewGuid():N}");
        var p1 = await api.CreateProductAsync(refs, $"P-{Guid.NewGuid():N}", 100m, RandomBarcode());

        var enter = await api.Http.PostAsJsonAsync("/api/inventory/enters", new
        {
            date = DateTime.UtcNow, storeId = refs.StoreId, currencyId = refs.CurrencyId,
            notes = "seed", lines = new[] { new { productId = p1, quantity = 2m, unitCost = 50m } },
        });
        enter.EnsureSuccessStatusCode();
        var eid = (await enter.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("id").GetString();
        (await api.Http.PostAsJsonAsync($"/api/inventory/enters/{eid}/post", new { })).EnsureSuccessStatusCode();

        var demand = await api.Http.PostAsJsonAsync("/api/sales/demands", new
        {
            date = DateTime.UtcNow, customerId, storeId = refs.StoreId, currencyId = refs.CurrencyId,
            payment = 2, paidAmount = 0m, notes = "over",
            lines = new[] { new { productId = p1, quantity = 5m, unitPrice = 100m, discount = 0m, vatPercent = 12m } },
        });
        demand.EnsureSuccessStatusCode();
        var did = (await demand.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("id").GetString();
        using var post = await api.Http.PostAsJsonAsync($"/api/sales/demands/{did}/post", new { });
        ((int)post.StatusCode).Should().Be(409);
        (await api.StockOfAsync(refs.StoreId, p1)).Should().Be(2m);
    }

    [Fact]
    public async Task Tenant_isolation_demand()
    {
        var a = new ApiActor(_factory.CreateClient());
        var b = new ApiActor(_factory.CreateClient());
        await a.SignupAndLoginAsync($"dem-iso-a-{Guid.NewGuid():N}");
        await b.SignupAndLoginAsync($"dem-iso-b-{Guid.NewGuid():N}");
        var refsA = await a.LoadRefsAsync();
        var customerA = await a.CreateCounterpartyAsync($"C-{Guid.NewGuid():N}");
        var pA = await a.CreateProductAsync(refsA, $"PA-{Guid.NewGuid():N}", 100m, RandomBarcode());

        var demand = await a.Http.PostAsJsonAsync("/api/sales/demands", new
        {
            date = DateTime.UtcNow, customerId = customerA, storeId = refsA.StoreId, currencyId = refsA.CurrencyId,
            payment = 2, paidAmount = 0m, notes = "iso",
            lines = new[] { new { productId = pA, quantity = 1m, unitPrice = 10m, discount = 0m, vatPercent = 12m } },
        });
        demand.EnsureSuccessStatusCode();
        var did = (await demand.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("id").GetString();

        var bList = await b.ListAsync("/api/sales/demands?pageSize=200");
        bList.Should().NotContain(x => x.GetProperty("id").GetString() == did);
        using var direct = await b.Http.GetAsync($"/api/sales/demands/{did}");
        direct.StatusCode.Should().Be(System.Net.HttpStatusCode.NotFound);
    }
}
