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

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

public sealed class FocasDriverPageFormSerializationTests
{
    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 FocasDriverOptions
        {
            Timeout = TimeSpan.FromSeconds(3),
            Probe = new FocasProbeOptions
            {
                Enabled = false,
                Interval = TimeSpan.FromSeconds(10),
                Timeout = TimeSpan.FromSeconds(4),
            },
            ProbeTimeoutSeconds = 30,
            AlarmProjection = new FocasAlarmProjectionOptions
            {
                Enabled = true,
                PollInterval = TimeSpan.FromSeconds(5),
            },
            HandleRecycle = new FocasHandleRecycleOptions
            {
                Enabled = true,
                Interval = TimeSpan.FromMinutes(30),
            },
            FixedTree = new FocasFixedTreeOptions
            {
                Enabled = true,
                PollInterval = TimeSpan.FromMilliseconds(500),
                ProgramPollInterval = TimeSpan.FromSeconds(2),
                TimerPollInterval = TimeSpan.FromSeconds(60),
            },
            Devices = [],
        };

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

        back.ShouldNotBeNull();
        back.Timeout.ShouldBe(TimeSpan.FromSeconds(3));
        back.Probe.Enabled.ShouldBeFalse();
        back.Probe.Interval.ShouldBe(TimeSpan.FromSeconds(10));
        back.Probe.Timeout.ShouldBe(TimeSpan.FromSeconds(4));
        back.ProbeTimeoutSeconds.ShouldBe(30);
        back.AlarmProjection.Enabled.ShouldBeTrue();
        back.AlarmProjection.PollInterval.ShouldBe(TimeSpan.FromSeconds(5));
        back.HandleRecycle.Enabled.ShouldBeTrue();
        back.HandleRecycle.Interval.ShouldBe(TimeSpan.FromMinutes(30));
        back.FixedTree.Enabled.ShouldBeTrue();
        back.FixedTree.PollInterval.ShouldBe(TimeSpan.FromMilliseconds(500));
        back.FixedTree.ProgramPollInterval.ShouldBe(TimeSpan.FromSeconds(2));
        back.FixedTree.TimerPollInterval.ShouldBe(TimeSpan.FromSeconds(60));
        back.Devices.ShouldBeEmpty();
    }

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

    [Fact]
    public void FormModel_RoundTrip_PreservesEditableFields()
    {
        var opts = new FocasDriverOptions
        {
            Timeout = TimeSpan.FromSeconds(4),
            Probe = new FocasProbeOptions
            {
                Enabled = true,
                Interval = TimeSpan.FromSeconds(8),
                Timeout = TimeSpan.FromSeconds(3),
            },
            ProbeTimeoutSeconds = 25,
            AlarmProjection = new FocasAlarmProjectionOptions
            {
                Enabled = true,
                PollInterval = TimeSpan.FromSeconds(3),
            },
            HandleRecycle = new FocasHandleRecycleOptions
            {
                Enabled = false,
                Interval = TimeSpan.FromHours(2),
            },
            FixedTree = new FocasFixedTreeOptions
            {
                Enabled = true,
                PollInterval = TimeSpan.FromMilliseconds(200),
                ProgramPollInterval = TimeSpan.FromSeconds(5),
                TimerPollInterval = TimeSpan.FromSeconds(45),
            },
        };

        var form = FocasDriverForm.FormModel.FromOptions(opts);
        var roundTripped = form.ToOptions([]);

        roundTripped.Timeout.ShouldBe(TimeSpan.FromSeconds(4));
        roundTripped.Probe.Enabled.ShouldBeTrue();
        roundTripped.Probe.Interval.ShouldBe(TimeSpan.FromSeconds(8));
        roundTripped.Probe.Timeout.ShouldBe(TimeSpan.FromSeconds(3));
        roundTripped.ProbeTimeoutSeconds.ShouldBe(25);
        roundTripped.AlarmProjection.Enabled.ShouldBeTrue();
        roundTripped.AlarmProjection.PollInterval.ShouldBe(TimeSpan.FromSeconds(3));
        roundTripped.HandleRecycle.Enabled.ShouldBeFalse();
        roundTripped.HandleRecycle.Interval.ShouldBe(TimeSpan.FromHours(2));
        roundTripped.FixedTree.Enabled.ShouldBeTrue();
        roundTripped.FixedTree.PollInterval.ShouldBe(TimeSpan.FromMilliseconds(200));
        roundTripped.FixedTree.ProgramPollInterval.ShouldBe(TimeSpan.FromSeconds(5));
        roundTripped.FixedTree.TimerPollInterval.ShouldBe(TimeSpan.FromSeconds(45));
    }

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

    [Fact]
    public void Device_list_survives_form_serialize_round_trip()
    {
        var devices = new List<FocasDeviceOptions>
        {
            new("192.168.0.10:8193", "CNC1", FocasCncSeries.Thirty_i),
            new("192.168.0.20:8193", "CNC2", FocasCncSeries.Zero_i_F),
        };
        var opts = new FocasDriverForm.FormModel().ToOptions(devices);
        var json = JsonSerializer.Serialize(opts, TestJsonOpts);
        var back = JsonSerializer.Deserialize<FocasDriverOptions>(json, TestJsonOpts)!;
        back.Devices.Count.ShouldBe(2);
        back.Devices[0].HostAddress.ShouldBe("192.168.0.10:8193");
        back.Devices[0].Series.ShouldBe(FocasCncSeries.Thirty_i);
        back.Devices[1].Series.ShouldBe(FocasCncSeries.Zero_i_F);
    }
}
