using Microsoft.EntityFrameworkCore;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Admin.Services;
using ZB.MOM.WW.OtOpcUa.Configuration;
using ZB.MOM.WW.OtOpcUa.Configuration.Entities;
using ZB.MOM.WW.OtOpcUa.Configuration.Enums;

namespace ZB.MOM.WW.OtOpcUa.Admin.Tests;

[Trait("Category", "Unit")]
public sealed class ClusterNodeServiceTests
{
    [Fact]
    public void IsStale_NullLastSeen_Returns_True()
    {
        var node = NewNode("A", RedundancyRole.Primary, lastSeenAt: null);
        ClusterNodeService.IsStale(node).ShouldBeTrue();
    }

    [Fact]
    public void IsStale_RecentLastSeen_Returns_False()
    {
        var node = NewNode("A", RedundancyRole.Primary, lastSeenAt: DateTime.UtcNow.AddSeconds(-5));
        ClusterNodeService.IsStale(node).ShouldBeFalse();
    }

    [Fact]
    public void IsStale_Old_LastSeen_Returns_True()
    {
        var node = NewNode("A", RedundancyRole.Primary,
            lastSeenAt: DateTime.UtcNow - ClusterNodeService.StaleThreshold - TimeSpan.FromSeconds(1));
        ClusterNodeService.IsStale(node).ShouldBeTrue();
    }

    [Fact]
    public async Task ListByClusterAsync_OrdersByServiceLevelBase_Descending_Then_NodeId()
    {
        using var ctx = NewContext();
        ctx.ClusterNodes.AddRange(
            NewNode("B-low", RedundancyRole.Secondary, serviceLevelBase: 150, clusterId: "c1"),
            NewNode("A-high", RedundancyRole.Primary, serviceLevelBase: 200, clusterId: "c1"),
            NewNode("other-cluster", RedundancyRole.Primary, serviceLevelBase: 200, clusterId: "c2"));
        await ctx.SaveChangesAsync();

        var svc = new ClusterNodeService(ctx);
        var rows = await svc.ListByClusterAsync("c1", CancellationToken.None);

        rows.Count.ShouldBe(2);
        rows[0].NodeId.ShouldBe("A-high");   // higher ServiceLevelBase first
        rows[1].NodeId.ShouldBe("B-low");
    }

    private static ClusterNode NewNode(
        string nodeId,
        RedundancyRole role,
        DateTime? lastSeenAt = null,
        int serviceLevelBase = 200,
        string clusterId = "c1") => new()
    {
        NodeId = nodeId,
        ClusterId = clusterId,
        RedundancyRole = role,
        Host = $"{nodeId}.example",
        ApplicationUri = $"urn:{nodeId}",
        ServiceLevelBase = (byte)serviceLevelBase,
        LastSeenAt = lastSeenAt,
        CreatedBy = "test",
    };

    private static OtOpcUaConfigDbContext NewContext()
    {
        var opts = new DbContextOptionsBuilder<OtOpcUaConfigDbContext>()
            .UseInMemoryDatabase(Guid.NewGuid().ToString())
            .Options;
        return new OtOpcUaConfigDbContext(opts);
    }
}
