using System.Text;
using System.Text.Json;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Runtime.Drivers;

namespace ZB.MOM.WW.OtOpcUa.Runtime.Tests.Drivers;

public sealed class DeploymentArtifactTests
{
    /// <summary>Verifies that empty blob returns empty list.</summary>
    [Fact]
    public void Empty_blob_returns_empty_list()
    {
        DeploymentArtifact.ParseDriverInstances(ReadOnlySpan<byte>.Empty).ShouldBeEmpty();
    }

    /// <summary>Verifies that malformed JSON returns empty list.</summary>
    [Fact]
    public void Malformed_json_returns_empty_list()
    {
        DeploymentArtifact.ParseDriverInstances(Encoding.UTF8.GetBytes("not json")).ShouldBeEmpty();
    }

    /// <summary>Verifies that snapshot without DriverInstances returns empty.</summary>
    [Fact]
    public void Snapshot_without_DriverInstances_returns_empty()
    {
        var blob = Encoding.UTF8.GetBytes("{\"Clusters\":[]}");
        DeploymentArtifact.ParseDriverInstances(blob).ShouldBeEmpty();
    }

    /// <summary>Verifies that driver instances are parsed from composer-shaped blob.</summary>
    [Fact]
    public void Parses_driver_instances_from_composer_shaped_blob()
    {
        // Mirrors the shape ConfigComposer.SnapshotAndFlattenAsync emits — Pascal-case fields
        // serialised directly off the EF entity.
        var rowId = Guid.NewGuid();
        var blob = JsonSerializer.SerializeToUtf8Bytes(new
        {
            DriverInstances = new[]
            {
                new
                {
                    DriverInstanceRowId = rowId,
                    DriverInstanceId = "DI-modbus-1",
                    Name = "Modbus Line A",
                    DriverType = "Modbus",
                    Enabled = true,
                    DriverConfig = "{\"host\":\"127.0.0.1\"}",
                },
                new
                {
                    DriverInstanceRowId = Guid.NewGuid(),
                    DriverInstanceId = "DI-disabled",
                    Name = "Decommissioned",
                    DriverType = "AbCip",
                    Enabled = false,
                    DriverConfig = "{}",
                },
            },
        });

        var specs = DeploymentArtifact.ParseDriverInstances(blob);

        specs.Count.ShouldBe(2);
        specs[0].DriverInstanceRowId.ShouldBe(rowId);
        specs[0].DriverInstanceId.ShouldBe("DI-modbus-1");
        specs[0].DriverType.ShouldBe("Modbus");
        specs[0].Enabled.ShouldBeTrue();
        specs[0].DriverConfig.ShouldContain("127.0.0.1");
        specs[1].Enabled.ShouldBeFalse();
    }

    /// <summary>Verifies that ParseComposition returns empty for empty blob.</summary>
    [Fact]
    public void ParseComposition_returns_empty_for_empty_blob()
    {
        var c = DeploymentArtifact.ParseComposition(ReadOnlySpan<byte>.Empty);
        c.EquipmentNodes.ShouldBeEmpty();
        c.DriverInstancePlans.ShouldBeEmpty();
        c.ScriptedAlarmPlans.ShouldBeEmpty();
    }

    /// <summary>Verifies that ParseComposition reads all three entity classes sorted by ID.</summary>
    [Fact]
    public void ParseComposition_reads_all_three_entity_classes_sorted_by_id()
    {
        var blob = JsonSerializer.SerializeToUtf8Bytes(new
        {
            Equipment = new[]
            {
                new { EquipmentId = "eq-z", MachineCode = "Z", UnsLineId = "line-1" },
                new { EquipmentId = "eq-a", MachineCode = "A", UnsLineId = "line-1" },
            },
            DriverInstances = new[]
            {
                new { DriverInstanceId = "drv-1", DriverType = "Modbus", DriverConfig = "{}" },
            },
            ScriptedAlarms = new[]
            {
                new
                {
                    ScriptedAlarmId = "alarm-1",
                    EquipmentId = "eq-a",
                    PredicateScriptId = "script-1",
                    MessageTemplate = "high",
                },
            },
        });

        var c = DeploymentArtifact.ParseComposition(blob);

        c.EquipmentNodes.Select(e => e.EquipmentId).ShouldBe(new[] { "eq-a", "eq-z" });
        c.DriverInstancePlans.Single().DriverInstanceId.ShouldBe("drv-1");
        c.ScriptedAlarmPlans.Single().ScriptedAlarmId.ShouldBe("alarm-1");
    }

    /// <summary>Verifies that specs missing required fields are dropped.</summary>
    [Fact]
    public void Spec_missing_required_fields_is_dropped()
    {
        var blob = JsonSerializer.SerializeToUtf8Bytes(new
        {
            DriverInstances = new object[]
            {
                new { Name = "no-id" },
                new
                {
                    DriverInstanceId = "DI-ok",
                    DriverType = "Modbus",
                    DriverConfig = "{}",
                },
            },
        });

        var specs = DeploymentArtifact.ParseDriverInstances(blob);

        specs.Single().DriverInstanceId.ShouldBe("DI-ok");
    }
}
