using ZB.MOM.WW.ScadaBridge.Commons.Messages.Audit;
using ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;

namespace ZB.MOM.WW.ScadaBridge.Commons.Tests.Messages;

/// <summary>
/// Site Call Audit (#22): construction, value-equality and optionality tests
/// for the Site Calls UI query / KPI / detail message contracts. Mirrors the
/// Notification Outbox <c>NotificationMessagesTests</c> coverage of the read
/// side, scoped to the contracts the Site Calls page consumes.
/// </summary>
public class SiteCallQueriesTests
{
    [Fact]
    public void SiteCallQueryRequest_PositionalConstruction_SetsAllFields()
    {
        var afterCreated = DateTime.UtcNow;
        var afterId = Guid.NewGuid();
        var request = new SiteCallQueryRequest(
            "corr-1", "Parked", "plant-a", "ApiOutbound", "ERP.GetOrder", true,
            new DateTime(2026, 5, 1), new DateTime(2026, 5, 20), afterCreated, afterId, 50);

        Assert.Equal("corr-1", request.CorrelationId);
        Assert.Equal("Parked", request.StatusFilter);
        Assert.Equal("plant-a", request.SourceSiteFilter);
        Assert.Equal("ApiOutbound", request.ChannelFilter);
        Assert.Equal("ERP.GetOrder", request.TargetKeyword);
        Assert.True(request.StuckOnly);
        Assert.Equal(new DateTime(2026, 5, 1), request.FromUtc);
        Assert.Equal(new DateTime(2026, 5, 20), request.ToUtc);
        Assert.Equal(afterCreated, request.AfterCreatedAtUtc);
        Assert.Equal(afterId, request.AfterId);
        Assert.Equal(50, request.PageSize);
    }

    [Fact]
    public void SiteCallQueryRequest_AllowsNullOptionalFilters()
    {
        var request = new SiteCallQueryRequest(
            "corr-2", null, null, null, null, false, null, null, null, null, 25);

        Assert.Null(request.StatusFilter);
        Assert.Null(request.SourceSiteFilter);
        Assert.Null(request.ChannelFilter);
        Assert.Null(request.TargetKeyword);
        Assert.False(request.StuckOnly);
        Assert.Null(request.FromUtc);
        Assert.Null(request.AfterId);
    }

    [Fact]
    public void SiteCallQueryResponse_ValueEquality_EqualWhenAllFieldsMatch()
    {
        var a = new SiteCallQueryResponse("c", true, null, Array.Empty<SiteCallSummary>(), null, null);
        var b = new SiteCallQueryResponse("c", true, null, Array.Empty<SiteCallSummary>(), null, null);

        Assert.Equal(a, b);
        Assert.Equal(a.GetHashCode(), b.GetHashCode());
    }

    [Fact]
    public void SiteCallSummary_CarriesEntityColumnsAndStuckFlag()
    {
        var id = Guid.NewGuid();
        var created = DateTime.UtcNow.AddMinutes(-30);
        var summary = new SiteCallSummary(
            id, "plant-a", "DbOutbound", "InventoryDb", "Retrying", 3,
            "transient 503", 503, created, created.AddMinutes(1), null, IsStuck: true);

        Assert.Equal(id, summary.TrackedOperationId);
        Assert.Equal("DbOutbound", summary.Channel);
        Assert.Equal("InventoryDb", summary.Target);
        Assert.Equal("Retrying", summary.Status);
        Assert.Equal(3, summary.RetryCount);
        Assert.Equal(503, summary.HttpStatus);
        Assert.Null(summary.TerminalAtUtc);
        Assert.True(summary.IsStuck);
    }

    [Fact]
    public void SiteCallDetailResponse_MissingRow_HasNullDetail()
    {
        var response = new SiteCallDetailResponse("c", false, "site call not found", null);

        Assert.False(response.Success);
        Assert.Null(response.Detail);
        Assert.Equal("site call not found", response.ErrorMessage);
    }

    [Fact]
    public void SiteCallKpiResponse_FailureShape_ZeroesKpiFields()
    {
        var response = new SiteCallKpiResponse(
            "c", Success: false, ErrorMessage: "db down",
            BufferedCount: 0, ParkedCount: 0, FailedLastInterval: 0,
            DeliveredLastInterval: 0, OldestPendingAge: null, StuckCount: 0);

        Assert.False(response.Success);
        Assert.Equal("db down", response.ErrorMessage);
        Assert.Equal(0, response.BufferedCount);
        Assert.Null(response.OldestPendingAge);
    }

    [Fact]
    public void PerSiteSiteCallKpiResponse_CarriesPerSiteSnapshots()
    {
        var response = new PerSiteSiteCallKpiResponse(
            "c", true, null,
            new[]
            {
                new SiteCallSiteKpiSnapshot("plant-a", 4, 1, 0, 9, TimeSpan.FromMinutes(15), 2),
            });

        Assert.True(response.Success);
        var site = Assert.Single(response.Sites);
        Assert.Equal("plant-a", site.SourceSite);
        Assert.Equal(4, site.BufferedCount);
        Assert.Equal(2, site.StuckCount);
        Assert.Equal(TimeSpan.FromMinutes(15), site.OldestPendingAge);
    }

    [Fact]
    public void SiteCallKpiSnapshot_OldestPendingAge_IsNullableForEmptyTable()
    {
        var snapshot = new SiteCallKpiSnapshot(0, 0, 0, 0, null, 0);
        Assert.Null(snapshot.OldestPendingAge);
    }
}
