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

    [Fact]
    public async Task Product_create_writes_audit_entry()
    {
        var api = new ApiActor(_factory.CreateClient());
        await api.SignupAndLoginAsync($"audit-{Guid.NewGuid():N}");
        var refs = await api.LoadRefsAsync();

        var pid = await api.CreateProductAsync(refs, $"AUD-{Guid.NewGuid():N}", 100m, RandomBarcode());

        var log = await api.GetJsonAsync("/api/admin/audit-log?entityType=Product&pageSize=20");
        var items = log.GetProperty("items").EnumerateArray().ToList();
        var entry = items.First(x => x.GetProperty("entityId").GetString() == pid);
        entry.GetProperty("action").GetString().Should().Be("create");
        entry.GetProperty("entityType").GetString().Should().Be("Product");
        entry.GetProperty("changesJson").GetString().Should().Contain("\"after\"");
    }

    [Fact]
    public async Task Counterparty_update_diff_contains_before_after()
    {
        var api = new ApiActor(_factory.CreateClient());
        await api.SignupAndLoginAsync($"audit-upd-{Guid.NewGuid():N}");
        var cid = await api.CreateCounterpartyAsync($"Init-{Guid.NewGuid():N}");

        // Обновляем — меняем имя.
        var newName = $"Renamed-{Guid.NewGuid():N}";
        var resp = await api.Http.PutAsJsonAsync($"/api/catalog/counterparties/{cid}", new
        {
            name = newName, legalName = (string?)null, type = 0,
            bin = "987654321098", iin = (string?)null, taxNumber = (string?)null,
            countryId = (string?)null, address = "Алматы", phone = "+77000000000",
            email = "x@y.kz", bankName = (string?)null, bankAccount = (string?)null,
            bik = (string?)null, contactPerson = "X", notes = (string?)null,
        });
        resp.EnsureSuccessStatusCode();

        var log = await api.GetJsonAsync($"/api/admin/audit-log?entityType=Counterparty&entityId={cid}");
        var items = log.GetProperty("items").EnumerateArray().ToList();
        items.Should().Contain(x => x.GetProperty("action").GetString() == "update");
        var update = items.First(x => x.GetProperty("action").GetString() == "update");
        var diff = update.GetProperty("changesJson").GetString()!;
        diff.Should().Contain("\"before\"");
        diff.Should().Contain("\"after\"");
        diff.Should().Contain(newName);
    }

    [Fact]
    public async Task Tenant_isolation_audit_log()
    {
        var a = new ApiActor(_factory.CreateClient());
        var b = new ApiActor(_factory.CreateClient());
        await a.SignupAndLoginAsync($"audit-iso-a-{Guid.NewGuid():N}");
        await b.SignupAndLoginAsync($"audit-iso-b-{Guid.NewGuid():N}");
        var refsA = await a.LoadRefsAsync();

        var pidA = await a.CreateProductAsync(refsA, $"P-{Guid.NewGuid():N}", 100m, RandomBarcode());

        // A видит свою запись.
        var logA = await a.GetJsonAsync($"/api/admin/audit-log?entityId={pidA}");
        logA.GetProperty("items").EnumerateArray().Should().Contain(
            x => x.GetProperty("entityId").GetString() == pidA);

        // B не видит чужую запись (query-filter по OrganizationId).
        var logB = await b.GetJsonAsync($"/api/admin/audit-log?entityId={pidA}");
        logB.GetProperty("items").EnumerateArray().Should().BeEmpty();
    }
}
