using System.Text.Json;
using System.Text.Json.Serialization;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Forms;
using ZB.MOM.WW.OtOpcUa.Driver.AbCip;

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

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

    private static readonly JsonSerializerOptions TestJsonOpts = new()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        UnmappedMemberHandling = JsonUnmappedMemberHandling.Skip,
    };

    [Fact]
    public void RoundTrip_PreservesKnownFields()
    {
        var original = new AbCipDriverOptions
        {
            Timeout = TimeSpan.FromSeconds(5),
            EnableControllerBrowse = true,
            EnableAlarmProjection = true,
            AlarmPollInterval = TimeSpan.FromSeconds(2),
            EnableDeclarationOnlyUdtGrouping = true,
            Probe = new AbCipProbeOptions
            {
                Enabled = true,
                Interval = TimeSpan.FromSeconds(10),
                Timeout = TimeSpan.FromSeconds(3),
                ProbeTagPath = "Program:Main.HealthBit",
            },
            ProbeTimeoutSeconds = 10,
            Devices =
            [
                new AbCipDeviceOptions("ab://10.0.0.1/1,0", AbCipPlcFamily.ControlLogix, "PLC-1"),
            ],
        };

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

        back.ShouldNotBeNull();
        back.Timeout.ShouldBe(TimeSpan.FromSeconds(5));
        back.EnableControllerBrowse.ShouldBeTrue();
        back.EnableAlarmProjection.ShouldBeTrue();
        back.AlarmPollInterval.ShouldBe(TimeSpan.FromSeconds(2));
        back.EnableDeclarationOnlyUdtGrouping.ShouldBeTrue();
        back.Probe.Enabled.ShouldBeTrue();
        back.Probe.Interval.ShouldBe(TimeSpan.FromSeconds(10));
        back.Probe.Timeout.ShouldBe(TimeSpan.FromSeconds(3));
        back.Probe.ProbeTagPath.ShouldBe("Program:Main.HealthBit");
        back.ProbeTimeoutSeconds.ShouldBe(10);
        back.Devices.Count.ShouldBe(1);
        back.Devices[0].HostAddress.ShouldBe("ab://10.0.0.1/1,0");
        back.Devices[0].PlcFamily.ShouldBe(AbCipPlcFamily.ControlLogix);
    }

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

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

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

    // v3 Batch-2 (WP3): the embedded-Devices CollectionEditor + AbCipDeviceRow retired — devices are now
    // separate Device entities authored via the raw-tree DeviceModal (AbCipDeviceModel, HostAddress/PlcFamily
    // into DeviceConfig). The former DeviceRow_* / ValidateDeviceRow_* tests were removed. The channel-config
    // FormModel now lives in AbCipDriverForm; the multi-device Devices array it preserves is covered below.

    [Fact]
    public void Device_list_survives_form_serialize_round_trip()
    {
        var devices = new List<AbCipDeviceOptions>
        {
            new("ab://10.0.0.1/1,0", AbCipPlcFamily.ControlLogix, "PLC-1"),
            new("ab://10.0.0.2/1,0", AbCipPlcFamily.CompactLogix, "PLC-2"),
        };
        var opts = new AbCipDriverForm.FormModel().ToOptions(devices);
        var json = JsonSerializer.Serialize(opts, TestJsonOpts);
        var back = JsonSerializer.Deserialize<AbCipDriverOptions>(json, TestJsonOpts)!;
        back.Devices.Count.ShouldBe(2);
        back.Devices[0].HostAddress.ShouldBe("ab://10.0.0.1/1,0");
        back.Devices[0].PlcFamily.ShouldBe(AbCipPlcFamily.ControlLogix);
        back.Devices[1].PlcFamily.ShouldBe(AbCipPlcFamily.CompactLogix);
    }
}
