using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.AdminUI.Uns.TagEditors;

namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Uns;

public sealed class CalculationTagConfigModelTests
{
    [Theory]
    [InlineData(null)]
    [InlineData("")]
    [InlineData("   ")]
    [InlineData("{}")]
    public void FromJson_returns_defaults_for_empty_input(string? json)
    {
        var m = CalculationTagConfigModel.FromJson(json);

        m.ScriptId.ShouldBe("");
        m.ChangeTriggered.ShouldBeTrue();   // default true
        m.TimerIntervalMs.ShouldBeNull();
    }

    [Fact]
    public void Round_trip_preserves_all_fields()
    {
        var m = new CalculationTagConfigModel
        {
            ScriptId = "SC-abc123",
            ChangeTriggered = false,
            TimerIntervalMs = 5000,
        };

        var m2 = CalculationTagConfigModel.FromJson(m.ToJson());

        m2.ScriptId.ShouldBe("SC-abc123");
        m2.ChangeTriggered.ShouldBeFalse();
        m2.TimerIntervalMs.ShouldBe(5000);
    }

    [Fact]
    public void ToJson_emits_camelCase_keys()
    {
        var json = new CalculationTagConfigModel
        {
            ScriptId = "SC-1",
            ChangeTriggered = true,
            TimerIntervalMs = 250,
        }.ToJson();

        json.ShouldContain("\"scriptId\":\"SC-1\"");
        json.ShouldContain("\"changeTriggered\":true");
        json.ShouldContain("\"timerIntervalMs\":250");
    }

    [Fact]
    public void ToJson_omits_timer_when_null()
    {
        var json = new CalculationTagConfigModel
        {
            ScriptId = "SC-1",
            ChangeTriggered = true,
            TimerIntervalMs = null,
        }.ToJson();

        json.ShouldNotContain("timerIntervalMs");
    }

    [Fact]
    public void FromJson_then_ToJson_preserves_unknown_keys()
    {
        var json = CalculationTagConfigModel
            .FromJson("""{"scriptId":"SC-1","futureKnob":42,"note":"keep me"}""")
            .ToJson();

        json.ShouldContain("futureKnob");
        json.ShouldContain("42");
        json.ShouldContain("keep me");
        json.ShouldContain("\"scriptId\":\"SC-1\"");
    }

    [Fact]
    public void Validate_requires_a_script()
    {
        new CalculationTagConfigModel { ScriptId = "", ChangeTriggered = true }
            .Validate().ShouldNotBeNull();
    }

    [Fact]
    public void Validate_requires_at_least_one_trigger()
    {
        new CalculationTagConfigModel { ScriptId = "SC-1", ChangeTriggered = false, TimerIntervalMs = null }
            .Validate().ShouldNotBeNull();
    }

    [Fact]
    public void Validate_rejects_sub_50ms_timer()
    {
        new CalculationTagConfigModel { ScriptId = "SC-1", ChangeTriggered = false, TimerIntervalMs = 49 }
            .Validate().ShouldNotBeNull();
    }

    [Fact]
    public void Validate_accepts_change_trigger_only()
    {
        new CalculationTagConfigModel { ScriptId = "SC-1", ChangeTriggered = true, TimerIntervalMs = null }
            .Validate().ShouldBeNull();
    }

    [Fact]
    public void Validate_accepts_timer_only()
    {
        new CalculationTagConfigModel { ScriptId = "SC-1", ChangeTriggered = false, TimerIntervalMs = 50 }
            .Validate().ShouldBeNull();
    }
}
