using System;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Host.Stability;

namespace ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Host.Tests;

[Trait("Category", "Unit")]
public sealed class RecyclePolicyTests
{
    [Fact]
    public void First_soft_recycle_is_allowed()
    {
        var p = new RecyclePolicy();
        p.TryRequestSoftRecycle(DateTime.UtcNow, out var reason).ShouldBeTrue();
        reason.ShouldBeNull();
    }

    [Fact]
    public void Second_soft_recycle_within_cap_is_blocked()
    {
        var p = new RecyclePolicy();
        var t0 = DateTime.UtcNow;
        p.TryRequestSoftRecycle(t0, out _).ShouldBeTrue();
        p.TryRequestSoftRecycle(t0.AddMinutes(30), out var reason).ShouldBeFalse();
        reason.ShouldContain("frequency cap");
    }

    [Fact]
    public void Recycle_after_cap_elapses_is_allowed_again()
    {
        var p = new RecyclePolicy();
        var t0 = DateTime.UtcNow;
        p.TryRequestSoftRecycle(t0, out _).ShouldBeTrue();
        p.TryRequestSoftRecycle(t0.AddHours(1).AddMinutes(1), out _).ShouldBeTrue();
    }

    [Fact]
    public void Scheduled_recycle_fires_once_per_day_at_local_3am()
    {
        var p = new RecyclePolicy();
        var last = DateTime.MinValue;

        p.ShouldSoftRecycleScheduled(new DateTime(2026, 4, 17, 2, 59, 0), ref last).ShouldBeFalse();
        p.ShouldSoftRecycleScheduled(new DateTime(2026, 4, 17, 3, 0, 0), ref last).ShouldBeTrue();
        p.ShouldSoftRecycleScheduled(new DateTime(2026, 4, 17, 3, 30, 0), ref last).ShouldBeFalse(
            "already fired today");
        p.ShouldSoftRecycleScheduled(new DateTime(2026, 4, 18, 3, 0, 0), ref last).ShouldBeTrue(
            "next day fires again");
    }
}
