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 CustomerReturnTests
{
    private readonly ApiFactory _factory;
    public CustomerReturnTests(ApiFactory factory) => _factory = factory;

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

    /// <summary>Создать продажу по чеку → создать возврат через create-return →
    /// провести возврат → stock увеличился обратно.</summary>
    [Fact]
    public async Task Create_return_from_sale_returns_stock()
    {
        var api = new ApiActor(_factory.CreateClient());
        await api.SignupAndLoginAsync($"crt-{Guid.NewGuid():N}");
        var refs = await api.LoadRefsAsync();
        var productId = await api.CreateProductAsync(refs, $"Prod-{Guid.NewGuid():N}", 200m, RandomBarcode());

        // Оприходовать 10 шт.
        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, quantity = 10m, unitCost = 50m } },
        });
        enter.EnsureSuccessStatusCode();
        var enterId = (await enter.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("id").GetString();
        (await api.Http.PostAsJsonAsync($"/api/inventory/enters/{enterId}/post", new { })).EnsureSuccessStatusCode();

        // Продать 4 шт.
        var sale = await api.Http.PostAsJsonAsync("/api/sales/retail", new
        {
            date = DateTime.UtcNow, storeId = refs.StoreId, retailPointId = (string?)null,
            customerId = (string?)null, currencyId = refs.CurrencyId,
            payment = 0, paidCash = 1000m, paidCard = 0m,
            lines = new[] { new { productId, quantity = 4m, unitPrice = 200m, discount = 0m, vatPercent = 12m } },
            notes = "sale",
        });
        sale.EnsureSuccessStatusCode();
        var saleId = (await sale.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("id").GetString();
        (await api.Http.PostAsJsonAsync($"/api/sales/retail/{saleId}/post", new { })).EnsureSuccessStatusCode();
        (await api.StockOfAsync(refs.StoreId, productId)).Should().Be(6m);

        // Создать возврат по чеку.
        using var createRet = await api.Http.PostAsJsonAsync($"/api/sales/retail/{saleId}/create-return", new { });
        createRet.IsSuccessStatusCode.Should().BeTrue($"create-return вернул {(int)createRet.StatusCode}: {await createRet.Content.ReadAsStringAsync()}");
        var ret = await createRet.Content.ReadFromJsonAsync<JsonElement>();
        ret.GetProperty("isReturn").GetBoolean().Should().BeTrue();
        ret.GetProperty("referenceSaleId").GetString().Should().Be(saleId);
        ret.GetProperty("lines").GetArrayLength().Should().Be(1);
        var retId = ret.GetProperty("id").GetString();

        // Провести возврат → товар возвращается на склад.
        using var post = await api.Http.PostAsJsonAsync($"/api/sales/retail/{retId}/post", new { });
        post.IsSuccessStatusCode.Should().BeTrue($"post возврата вернул {(int)post.StatusCode}: {await post.Content.ReadAsStringAsync()}");
        (await api.StockOfAsync(refs.StoreId, productId)).Should().Be(10m);

        // Повторный create-return должен ругаться — всё уже возвращено.
        using var second = await api.Http.PostAsJsonAsync($"/api/sales/retail/{saleId}/create-return", new { });
        ((int)second.StatusCode).Should().Be(400);
    }

    [Fact]
    public async Task Standalone_return_without_reference_works()
    {
        var api = new ApiActor(_factory.CreateClient());
        await api.SignupAndLoginAsync($"crt-std-{Guid.NewGuid():N}");
        var refs = await api.LoadRefsAsync();
        var productId = await api.CreateProductAsync(refs, $"Prod-{Guid.NewGuid():N}", 100m, RandomBarcode());

        // Создать возврат без референса (просто возврат «с улицы»).
        var resp = await api.Http.PostAsJsonAsync("/api/sales/retail", new
        {
            date = DateTime.UtcNow, storeId = refs.StoreId, retailPointId = (string?)null,
            customerId = (string?)null, currencyId = refs.CurrencyId,
            payment = 0, paidCash = 100m, paidCard = 0m,
            lines = new[] { new { productId, quantity = 1m, unitPrice = 100m, discount = 0m, vatPercent = 12m } },
            notes = "standalone-ret",
            isReturn = true,
        });
        resp.EnsureSuccessStatusCode();
        var retId = (await resp.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("id").GetString();

        // Провести → товар приходит на склад (даже если его там не было).
        (await api.Http.PostAsJsonAsync($"/api/sales/retail/{retId}/post", new { }))
            .IsSuccessStatusCode.Should().BeTrue();
        (await api.StockOfAsync(refs.StoreId, productId)).Should().Be(1m);
    }

    [Fact]
    public async Task Cannot_unpost_sale_with_active_return()
    {
        var api = new ApiActor(_factory.CreateClient());
        await api.SignupAndLoginAsync($"crt-unp-{Guid.NewGuid():N}");
        var refs = await api.LoadRefsAsync();
        var productId = await api.CreateProductAsync(refs, $"Prod-{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, quantity = 5m, unitCost = 50m } },
        });
        enter.EnsureSuccessStatusCode();
        var enterId = (await enter.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("id").GetString();
        (await api.Http.PostAsJsonAsync($"/api/inventory/enters/{enterId}/post", new { })).EnsureSuccessStatusCode();

        var sale = await api.Http.PostAsJsonAsync("/api/sales/retail", new
        {
            date = DateTime.UtcNow, storeId = refs.StoreId, retailPointId = (string?)null,
            customerId = (string?)null, currencyId = refs.CurrencyId,
            payment = 0, paidCash = 600m, paidCard = 0m,
            lines = new[] { new { productId, quantity = 3m, unitPrice = 200m, discount = 0m, vatPercent = 12m } },
            notes = "sale",
        });
        sale.EnsureSuccessStatusCode();
        var saleId = (await sale.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("id").GetString();
        (await api.Http.PostAsJsonAsync($"/api/sales/retail/{saleId}/post", new { })).EnsureSuccessStatusCode();

        var ret = await api.Http.PostAsJsonAsync($"/api/sales/retail/{saleId}/create-return", new { });
        ret.EnsureSuccessStatusCode();
        var retId = (await ret.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("id").GetString();
        (await api.Http.PostAsJsonAsync($"/api/sales/retail/{retId}/post", new { })).EnsureSuccessStatusCode();

        // Теперь оригинал нельзя распровести — есть проведённый возврат.
        using var unpost = await api.Http.PostAsJsonAsync($"/api/sales/retail/{saleId}/unpost", new { });
        ((int)unpost.StatusCode).Should().Be(409);
    }
}
