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

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

/// <summary>
/// Round-trip tests for the native-alarm sub-model's <c>historizeToAveva</c> opt-out
/// (the <c>TagConfig.alarm.historizeToAveva</c> bool?). Absent ⇒ null ⇒ the server's
/// <c>HistorianAdapterActor</c> "is not false" gate still historizes (default-on); explicit
/// <c>false</c> suppresses the durable AVEVA write. Mirrors the scripted-alarm opt-out posture.
/// </summary>
public sealed class NativeAlarmHistorizeModelTests
{
    [Fact]
    public void FromJson_no_alarm_object_means_not_an_alarm_tag()
    {
        var m = NativeAlarmModel.FromJson("""{"FullName":"Temp.HiHi"}""");

        m.IsAlarm.ShouldBeFalse();
        m.HistorizeToAveva.ShouldBeNull();
    }

    [Theory]
    [InlineData(null)]
    [InlineData("")]
    [InlineData("   ")]
    [InlineData("{}")]
    public void FromJson_returns_non_alarm_for_empty_input(string? json)
    {
        var m = NativeAlarmModel.FromJson(json);

        m.IsAlarm.ShouldBeFalse();
        m.HistorizeToAveva.ShouldBeNull();
    }

    [Fact]
    public void FromJson_alarm_without_historizeToAveva_is_null_default_on()
    {
        var m = NativeAlarmModel.FromJson(
            """{"FullName":"Temp.HiHi","alarm":{"alarmType":"OffNormalAlarm","severity":700}}""");

        m.IsAlarm.ShouldBeTrue();
        m.AlarmType.ShouldBe("OffNormalAlarm");
        m.Severity.ShouldBe(700);
        // Absent ⇒ null ⇒ historize (default-on at the gate).
        m.HistorizeToAveva.ShouldBeNull();
    }

    [Fact]
    public void FromJson_reads_historizeToAveva_true()
    {
        var m = NativeAlarmModel.FromJson(
            """{"alarm":{"alarmType":"LimitAlarm","severity":500,"historizeToAveva":true}}""");

        m.HistorizeToAveva.ShouldBe(true);
    }

    [Fact]
    public void FromJson_reads_historizeToAveva_false_opt_out()
    {
        var m = NativeAlarmModel.FromJson(
            """{"alarm":{"alarmType":"LimitAlarm","severity":500,"historizeToAveva":false}}""");

        m.HistorizeToAveva.ShouldBe(false);
    }

    [Fact]
    public void Round_trip_true_persists_true()
    {
        var m = NativeAlarmModel.FromJson(
            """{"alarm":{"alarmType":"LimitAlarm","severity":500}}""");
        m.HistorizeToAveva = true;

        var round = NativeAlarmModel.FromJson(m.ToJson());

        round.HistorizeToAveva.ShouldBe(true);
        round.IsAlarm.ShouldBeTrue();
    }

    [Fact]
    public void Round_trip_false_persists_false()
    {
        var m = NativeAlarmModel.FromJson(
            """{"alarm":{"alarmType":"LimitAlarm","severity":500}}""");
        m.HistorizeToAveva = false;

        var round = NativeAlarmModel.FromJson(m.ToJson());

        round.HistorizeToAveva.ShouldBe(false);
    }

    [Fact]
    public void Round_trip_null_omits_the_key_default_on()
    {
        var m = NativeAlarmModel.FromJson(
            """{"alarm":{"alarmType":"LimitAlarm","severity":500,"historizeToAveva":true}}""");
        m.HistorizeToAveva = null;

        var json = m.ToJson();
        json.ShouldNotContain("historizeToAveva");

        NativeAlarmModel.FromJson(json).HistorizeToAveva.ShouldBeNull();
    }

    [Fact]
    public void ToJson_preserves_unknown_keys_at_root_and_in_alarm()
    {
        var m = NativeAlarmModel.FromJson(
            """{"FullName":"Temp.HiHi","alarm":{"alarmType":"OffNormalAlarm","severity":700,"customAlarmKey":"keep-me"},"customRootKey":42}""");
        m.HistorizeToAveva = false;

        var json = m.ToJson();

        json.ShouldContain("FullName");
        json.ShouldContain("Temp.HiHi");
        json.ShouldContain("customRootKey");
        json.ShouldContain("customAlarmKey");
        json.ShouldContain("keep-me");
        json.ShouldContain("historizeToAveva");
    }
}
