using System.Text.Json;
using System.Text.Json.Serialization;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Driver.Modbus;

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

public sealed class ModbusDriverPageFormSerializationTests
{
    private static readonly JsonSerializerOptions _opts = new()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        WriteIndented = false,
    };

    [Fact]
    public void RoundTrip_PreservesKnownFields()
    {
        var original = new ModbusDriverOptions
        {
            Host = "10.0.0.42",
            Port = 5020,
            UnitId = 3,
            Timeout = TimeSpan.FromSeconds(5),
            MaxRegistersPerRead = 64,
            MaxRegistersPerWrite = 60,
            MaxCoilsPerRead = 500,
            MaxReadGap = 8,
            UseFC15ForSingleCoilWrites = true,
            UseFC16ForSingleRegisterWrites = true,
            DisableFC23 = true,
            WriteOnChangeOnly = true,
            AutoReconnect = false,
            Family = ModbusFamily.DL205,
            MelsecSubFamily = MelsecFamily.F_iQF,
            Probe = new ModbusProbeOptions
            {
                Enabled = false,
                Interval = TimeSpan.FromSeconds(10),
                Timeout = TimeSpan.FromSeconds(3),
                ProbeAddress = 7,
            },
            KeepAlive = new ModbusKeepAliveOptions
            {
                Enabled = false,
                Time = TimeSpan.FromSeconds(60),
                Interval = TimeSpan.FromSeconds(15),
                RetryCount = 5,
            },
            Reconnect = new ModbusReconnectOptions
            {
                InitialDelay = TimeSpan.FromSeconds(1),
                MaxDelay = TimeSpan.FromSeconds(60),
                BackoffMultiplier = 1.5,
            },
            ProbeTimeoutSeconds = 10,
        };

        var json = JsonSerializer.Serialize(original, _opts);
        var back = JsonSerializer.Deserialize<ModbusDriverOptions>(json, _opts);

        back.ShouldNotBeNull();
        back.Host.ShouldBe("10.0.0.42");
        back.Port.ShouldBe(5020);
        back.UnitId.ShouldBe((byte)3);
        back.Timeout.ShouldBe(TimeSpan.FromSeconds(5));
        back.MaxRegistersPerRead.ShouldBe((ushort)64);
        back.MaxRegistersPerWrite.ShouldBe((ushort)60);
        back.MaxCoilsPerRead.ShouldBe((ushort)500);
        back.MaxReadGap.ShouldBe((ushort)8);
        back.UseFC15ForSingleCoilWrites.ShouldBeTrue();
        back.UseFC16ForSingleRegisterWrites.ShouldBeTrue();
        back.DisableFC23.ShouldBeTrue();
        back.WriteOnChangeOnly.ShouldBeTrue();
        back.AutoReconnect.ShouldBeFalse();
        back.Family.ShouldBe(ModbusFamily.DL205);
        back.MelsecSubFamily.ShouldBe(MelsecFamily.F_iQF);
        back.Probe.Enabled.ShouldBeFalse();
        back.Probe.Interval.ShouldBe(TimeSpan.FromSeconds(10));
        back.Probe.Timeout.ShouldBe(TimeSpan.FromSeconds(3));
        back.Probe.ProbeAddress.ShouldBe((ushort)7);
        back.KeepAlive.Enabled.ShouldBeFalse();
        back.KeepAlive.Time.ShouldBe(TimeSpan.FromSeconds(60));
        back.KeepAlive.Interval.ShouldBe(TimeSpan.FromSeconds(15));
        back.KeepAlive.RetryCount.ShouldBe(5);
        back.Reconnect.InitialDelay.ShouldBe(TimeSpan.FromSeconds(1));
        back.Reconnect.MaxDelay.ShouldBe(TimeSpan.FromSeconds(60));
        back.Reconnect.BackoffMultiplier.ShouldBe(1.5);
        back.ProbeTimeoutSeconds.ShouldBe(10);
    }

    [Fact]
    public void Deserialize_DropsUnknownFields()
    {
        var jsonWithExtra = """{"unknownField":"old-value","probeTimeoutSeconds":10}""";

        var optsWithSkip = new JsonSerializerOptions(_opts)
        {
            UnmappedMemberHandling = JsonUnmappedMemberHandling.Skip,
        };

        var back = JsonSerializer.Deserialize<ModbusDriverOptions>(jsonWithExtra, optsWithSkip);
        back.ShouldNotBeNull();
        back.ProbeTimeoutSeconds.ShouldBe(10);
    }

    // v3 Batch-1 migration: the pre-declared Tags editor (ModbusDriverPage.ModbusTagRow +
    // ModbusDriverOptions.Tags) was retired — tags moved to the Raw tree (/raw, Batch 2). The former
    // TagRow_* / Tag_list_survives_* / ValidateRow_* / ToDefinition_preserves_* tests were removed.
    // The connection/protocol-field + enum-serialization coverage (ModbusFamily, MelsecFamily) is
    // retained by RoundTrip_PreservesKnownFields above unchanged.
}
