using ZB.MOM.WW.ScadaBridge.CLI.Commands;
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Management;

namespace ZB.MOM.WW.ScadaBridge.CLI.Tests;

/// <summary>
/// Regression tests for CLI-005 — malformed <c>--bindings</c> / <c>--overrides</c> JSON
/// previously threw unhandled exceptions instead of producing a clean validation error.
/// </summary>
public class InstanceArgumentParsingTests
{
    [Fact]
    public void ParseBindings_ValidJson_ReturnsPairs()
    {
        var ok = InstanceCommands.TryParseBindings(
            "[[\"Speed\", 5], [\"Mode\", 7]]", out var bindings, out var error);

        Assert.True(ok);
        Assert.Null(error);
        Assert.Equal(2, bindings!.Count);
        Assert.Equal(new ConnectionBinding("Speed", 5), bindings[0]);
        Assert.Equal(new ConnectionBinding("Mode", 7), bindings[1]);
    }

    [Fact]
    public void ParseBindings_MalformedJson_ReturnsErrorNotException()
    {
        var ok = InstanceCommands.TryParseBindings("not json", out var bindings, out var error);

        Assert.False(ok);
        Assert.Null(bindings);
        Assert.NotNull(error);
    }

    [Fact]
    public void ParseBindings_ShortPair_ReturnsErrorNotException()
    {
        // A pair with fewer than two elements previously threw ArgumentOutOfRangeException.
        var ok = InstanceCommands.TryParseBindings("[[\"Speed\"]]", out var bindings, out var error);

        Assert.False(ok);
        Assert.Null(bindings);
        Assert.NotNull(error);
    }

    [Fact]
    public void ParseBindings_WrongElementTypes_ReturnsErrorNotException()
    {
        // A non-string name / non-int id previously threw InvalidOperationException.
        var ok = InstanceCommands.TryParseBindings("[[5, \"Speed\"]]", out var bindings, out var error);

        Assert.False(ok);
        Assert.Null(bindings);
        Assert.NotNull(error);
    }

    [Fact]
    public void ParseBindings_JsonNull_ReturnsErrorNotException()
    {
        var ok = InstanceCommands.TryParseBindings("null", out var bindings, out var error);

        Assert.False(ok);
        Assert.Null(bindings);
        Assert.NotNull(error);
    }

    [Fact]
    public void ParseBindings_ThreeElementForm_CapturesReferenceOverride()
    {
        // The optional 3rd element carries the per-instance data-source reference
        // override (followup #4) so the CLI can SET it instead of always wiping it.
        var ok = InstanceCommands.TryParseBindings(
            "[[\"Speed\", 5, \"ns=2;s=Spd\"], [\"Mode\", 7]]", out var bindings, out var error);

        Assert.True(ok);
        Assert.Null(error);
        Assert.Equal(2, bindings!.Count);
        Assert.Equal(new ConnectionBinding("Speed", 5, "ns=2;s=Spd"), bindings[0]);
        // A 2-element entry still leaves the override null (template default applies).
        Assert.Equal(new ConnectionBinding("Mode", 7, null), bindings[1]);
        Assert.Null(bindings[1].DataSourceReferenceOverride);
    }

    [Fact]
    public void ParseBindings_ThirdElementExplicitNull_LeavesOverrideUnset()
    {
        var ok = InstanceCommands.TryParseBindings(
            "[[\"Speed\", 5, null]]", out var bindings, out var error);

        Assert.True(ok);
        Assert.Null(error);
        Assert.Single(bindings!);
        Assert.Null(bindings![0].DataSourceReferenceOverride);
    }

    [Fact]
    public void ParseBindings_ThirdElementWrongType_ReturnsErrorNotException()
    {
        // A non-string, non-null 3rd element is rejected with a clean error.
        var ok = InstanceCommands.TryParseBindings(
            "[[\"Speed\", 5, 99]]", out var bindings, out var error);

        Assert.False(ok);
        Assert.Null(bindings);
        Assert.NotNull(error);
    }

    [Fact]
    public void ParseBindings_FourElements_ReturnsErrorNotException()
    {
        var ok = InstanceCommands.TryParseBindings(
            "[[\"Speed\", 5, \"ref\", \"extra\"]]", out var bindings, out var error);

        Assert.False(ok);
        Assert.Null(bindings);
        Assert.NotNull(error);
    }

    [Fact]
    public void ParseOverrides_ValidJson_ReturnsDictionary()
    {
        var ok = InstanceCommands.TryParseOverrides(
            "{\"Speed\": \"100\", \"Mode\": null}", out var overrides, out var error);

        Assert.True(ok);
        Assert.Null(error);
        Assert.Equal(2, overrides!.Count);
        Assert.Equal("100", overrides["Speed"]);
        Assert.Null(overrides["Mode"]);
    }

    [Fact]
    public void ParseOverrides_MalformedJson_ReturnsErrorNotException()
    {
        var ok = InstanceCommands.TryParseOverrides("{bad json", out var overrides, out var error);

        Assert.False(ok);
        Assert.Null(overrides);
        Assert.NotNull(error);
    }

    [Fact]
    public void ParseOverrides_JsonNull_ReturnsErrorNotException()
    {
        var ok = InstanceCommands.TryParseOverrides("null", out var overrides, out var error);

        Assert.False(ok);
        Assert.Null(overrides);
        Assert.NotNull(error);
    }
}
