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.S7;

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

// v3 Batch-1 migration: the S7 driver page dropped its pre-declared Tags editor — tags now live in
// the Raw tree (/raw, Batch 2), and S7DriverOptions.Tags (the typed S7TagDefinition list) +
// S7DriverForm.S7TagRow were retired (the driver now consumes RawTags). The former tag-editor and
// tag-serialization tests (S7TagRow_*, TagList_SerializeRoundTrip_PreservesTags, and the tag legs of
// the round-trip tests) were removed. The connection/protocol-field + enum-serialization round-trip
// coverage (CpuType, S7DataType) is retained below unchanged.
public sealed class S7DriverPageFormSerializationTests
{
    private static readonly JsonSerializerOptions _opts = new()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        WriteIndented = false,
    };

    [Fact]
    public void RoundTrip_PreservesKnownFields()
    {
        var original = new S7DriverOptions
        {
            Host = "10.0.0.5",
            Port = 102,
            CpuType = S7CpuType.S71200,
            Rack = 0,
            Slot = 1,
            Timeout = TimeSpan.FromSeconds(10),
            Probe = new S7ProbeOptions
            {
                Enabled = false,
                Interval = TimeSpan.FromSeconds(15),
                Timeout = TimeSpan.FromSeconds(3),
            },
            ProbeTimeoutSeconds = 30,
        };

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

        back.ShouldNotBeNull();
        back.Host.ShouldBe("10.0.0.5");
        back.Port.ShouldBe(102);
        back.CpuType.ShouldBe(S7CpuType.S71200);
        back.Rack.ShouldBe((short)0);
        back.Slot.ShouldBe((short)1);
        back.Timeout.ShouldBe(TimeSpan.FromSeconds(10));
        back.Probe.ShouldNotBeNull();
        back.Probe.Enabled.ShouldBeFalse();
        back.Probe.Interval.ShouldBe(TimeSpan.FromSeconds(15));
        back.Probe.Timeout.ShouldBe(TimeSpan.FromSeconds(3));
        back.ProbeTimeoutSeconds.ShouldBe(30);
    }

    [Fact]
    public void Deserialize_DropsUnknownFields()
    {
        var jsonWithExtra = """{"unknownField":"old-value","probeTimeoutSeconds":12}""";
        var optsSkip = new JsonSerializerOptions(_opts)
        {
            UnmappedMemberHandling = JsonUnmappedMemberHandling.Skip,
        };
        var back = JsonSerializer.Deserialize<S7DriverOptions>(jsonWithExtra, optsSkip);
        back.ShouldNotBeNull();
        back.ProbeTimeoutSeconds.ShouldBe(12);
    }

    [Fact]
    public void FormModel_RoundTrip_PreservesEditableFields()
    {
        var opts = new S7DriverOptions
        {
            Host = "192.168.1.50",
            Port = 102,
            CpuType = S7CpuType.S7300,
            Rack = 0,
            Slot = 2,
            Timeout = TimeSpan.FromSeconds(7),
            Probe = new S7ProbeOptions
            {
                Enabled = true,
                Interval = TimeSpan.FromSeconds(8),
                Timeout = TimeSpan.FromSeconds(4),
            },
            ProbeTimeoutSeconds = 20,
        };

        var form = S7DriverForm.FormModel.FromOptions(opts);
        var roundTripped = form.ToOptions();

        roundTripped.Host.ShouldBe("192.168.1.50");
        roundTripped.Port.ShouldBe(102);
        roundTripped.CpuType.ShouldBe(S7CpuType.S7300);
        roundTripped.Rack.ShouldBe((short)0);
        roundTripped.Slot.ShouldBe((short)2);
        roundTripped.Timeout.ShouldBe(TimeSpan.FromSeconds(7));
        roundTripped.Probe.Enabled.ShouldBeTrue();
        roundTripped.Probe.Interval.ShouldBe(TimeSpan.FromSeconds(8));
        roundTripped.Probe.Timeout.ShouldBe(TimeSpan.FromSeconds(4));
        roundTripped.ProbeTimeoutSeconds.ShouldBe(20);
    }
}
