using System.Collections;
using ZB.MOM.WW.ScadaBridge.Commons.Types;

namespace ZB.MOM.WW.ScadaBridge.Commons.Tests.Types;

/// <summary>
/// Commons-010: coverage for <see cref="ScriptArgs.Normalize"/> — the script-call
/// parameter normalizer (dictionary / anonymous-object / primitive-rejection paths).
/// </summary>
public class ScriptArgsTests
{
    [Fact]
    public void Normalize_Null_ReturnsNull()
    {
        Assert.Null(ScriptArgs.Normalize(null));
    }

    [Fact]
    public void Normalize_ReadOnlyDictionary_ReturnedAsIs()
    {
        IReadOnlyDictionary<string, object?> input =
            new Dictionary<string, object?> { ["a"] = 1 };

        var result = ScriptArgs.Normalize(input);

        Assert.Same(input, result);
    }

    [Fact]
    public void Normalize_PlainDictionary_ReturnedAsIs()
    {
        // Dictionary<string,object?> implements IReadOnlyDictionary, so it matches the
        // first switch arm and is returned by reference (no defensive copy).
        var input = new Dictionary<string, object?> { ["a"] = 1 };

        var result = ScriptArgs.Normalize(input);

        Assert.Same(input, result);
        Assert.Equal(1, result!["a"]);
    }

    [Fact]
    public void Normalize_NonGenericDictionary_KeysStringified()
    {
        IDictionary raw = new Hashtable { [42] = "answer" };

        var result = ScriptArgs.Normalize(raw);

        Assert.Equal("answer", result!["42"]);
    }

    [Fact]
    public void Normalize_AnonymousObject_PropertiesBecomeEntries()
    {
        var result = ScriptArgs.Normalize(new { name = "Bob", count = 3 });

        Assert.Equal("Bob", result!["name"]);
        Assert.Equal(3, result["count"]);
    }

    [Theory]
    [InlineData(42)]
    [InlineData(true)]
    [InlineData(3.14)]
    public void Normalize_Primitive_Throws(object primitive)
    {
        Assert.Throws<ArgumentException>(() => ScriptArgs.Normalize(primitive));
    }

    [Fact]
    public void Normalize_String_Throws()
    {
        Assert.Throws<ArgumentException>(() => ScriptArgs.Normalize("hello"));
    }

    [Fact]
    public void Normalize_Decimal_Throws()
    {
        Assert.Throws<ArgumentException>(() => ScriptArgs.Normalize(9.99m));
    }
}
