using System.Text.Json;
using System.Text.Json.Serialization;
using Shouldly;
using Xunit;

namespace ZB.MOM.WW.OtOpcUa.Driver.S7.Tests;

/// <summary>
///     Regression guard for the 2026-06-19 enum-serialization bug. The AdminUI S7 page now
///     serialises <see cref="S7CpuType"/> as a STRING (its <c>_jsonOpts</c> gained a
///     <see cref="JsonStringEnumConverter"/>). This proves the factory parses that AdminUI-shaped
///     blob and round-trips the enum, and documents that the pre-fix NUMERIC form — which the old
///     page emitted — threw because <c>S7DriverConfigDto.CpuType</c> is <c>string?</c>.
/// </summary>
public sealed class S7DriverConfigEnumSerializationTests
{
    // Mirrors the (now fixed) AdminUI S7DriverPage._jsonOpts: camelCase + string enums.
    private static readonly JsonSerializerOptions _adminPageOpts = new()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        Converters = { new JsonStringEnumConverter() },
    };

    /// <summary>Verifies the factory parses an AdminUI-authored (string-enum) S7 config and
    /// preserves the CpuType.</summary>
    [Fact]
    public void Factory_parses_admin_authored_string_enum_config()
    {
        var opts = new S7DriverOptions { Host = "10.0.0.5", Port = 102, CpuType = S7CpuType.S71500, Rack = 0, Slot = 1 };
        var blob = JsonSerializer.Serialize(opts, _adminPageOpts);
        // The fixed AdminUI page must emit the enum as a string, not a number.
        blob.ShouldContain("\"cpuType\":\"S71500\"");

        var parsed = S7DriverFactoryExtensions.ParseOptions("s7-test", blob);
        parsed.CpuType.ShouldBe(S7CpuType.S71500);
    }

    /// <summary>Documents the original bug: the pre-fix AdminUI page emitted a numeric enum
    /// (<c>"cpuType":40</c>) which the string-typed config DTO cannot bind, so the factory throws.</summary>
    [Fact]
    public void Factory_throws_on_the_numeric_enum_form_the_pre_fix_page_emitted()
    {
        // 40 == (int)S7CpuType.S71500 — exactly what the pre-fix page (no converter) wrote for S71500.
        // The throw comes from binding a JSON number to the DTO's string? CpuType, so it fires for any number.
        const string numericBlob = "{\"host\":\"10.0.0.5\",\"port\":102,\"cpuType\":40,\"rack\":0,\"slot\":1}";
        Should.Throw<Exception>(() => S7DriverFactoryExtensions.ParseOptions("s7-test", numericBlob));
    }
}
