using System.Text.Json;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Instances;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.InboundApi;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Notifications;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Scripts;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Sites;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Templates;
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
using ZB.MOM.WW.ScadaBridge.Commons.Types.Transport;
using ZB.MOM.WW.ScadaBridge.Transport.Import;
using ZB.MOM.WW.ScadaBridge.Transport.Serialization;

namespace ZB.MOM.WW.ScadaBridge.Transport.Tests.Import;

/// <summary>
/// Tests for <see cref="ArtifactDiff"/>: the structured per-line Myers code diff
/// embedded in <c>FieldDiffJson</c> (T20) and the M8 Site / DataConnection /
/// Instance compares. The diff records are private, so assertions parse the
/// serialized <see cref="ImportPreviewItem.FieldDiffJson"/>.
/// </summary>
public sealed class ArtifactDiffTests
{
    private readonly ArtifactDiff _diff = new();

    // ---- JSON inspection helpers ----

    private static JsonElement Changes(ImportPreviewItem item)
    {
        Assert.NotNull(item.FieldDiffJson);
        using var doc = JsonDocument.Parse(item.FieldDiffJson!);
        // Clone so the element survives the using-scope disposal.
        return doc.RootElement.GetProperty("changes").Clone();
    }

    private static JsonElement ChangeFor(ImportPreviewItem item, string field)
    {
        foreach (var c in Changes(item).EnumerateArray())
        {
            if (c.GetProperty("field").GetString() == field)
            {
                return c.Clone();
            }
        }

        Assert.Fail($"No change for field '{field}'. JSON: {item.FieldDiffJson}");
        return default; // unreachable
    }

    private static IReadOnlyList<(string Op, string Text)> Hunks(JsonElement change)
    {
        var lineDiff = change.GetProperty("lineDiff");
        var hunks = new List<(string, string)>();
        foreach (var h in lineDiff.GetProperty("hunks").EnumerateArray())
        {
            hunks.Add((h.GetProperty("op").GetString()!, h.GetProperty("text").GetString()!));
        }

        return hunks;
    }

    // ============ T20: structured per-line code diff ============

    [Fact]
    public void SharedScript_ModifiedCode_EmitsStructuredLineDiff()
    {
        var existing = new SharedScript("calc", "var a = 1;\nvar b = 2;\nreturn a + b;");
        var incoming = new SharedScriptDto(
            Name: "calc",
            Code: "var a = 1;\nvar b = 20;\nreturn a + b;",
            ParameterDefinitions: existing.ParameterDefinitions,
            ReturnDefinition: existing.ReturnDefinition);

        var item = _diff.CompareSharedScript(incoming, existing);

        Assert.Equal(ConflictKind.Modified, item.Kind);
        var change = ChangeFor(item, "Code");
        // Compact summary retained for fallback.
        Assert.Equal("<3 lines>", change.GetProperty("oldValue").GetString());
        Assert.Equal("<3 lines>", change.GetProperty("newValue").GetString());

        var lineDiff = change.GetProperty("lineDiff");
        Assert.False(lineDiff.GetProperty("truncated").GetBoolean());
        Assert.Equal(1, lineDiff.GetProperty("addedCount").GetInt32());
        Assert.Equal(1, lineDiff.GetProperty("removedCount").GetInt32());

        var hunks = Hunks(change);
        // The changed middle line shows as a remove + add; unchanged lines are context.
        Assert.Contains(("remove", "var b = 2;"), hunks);
        Assert.Contains(("add", "var b = 20;"), hunks);
        Assert.Contains(("context", "var a = 1;"), hunks);
        Assert.Contains(("context", "return a + b;"), hunks);
        // Not a "<N lines>"-only marker any more.
        Assert.DoesNotContain(hunks, h => h.Text.Contains("lines>"));
    }

    [Fact]
    public void SharedScript_IdenticalCode_NoChange()
    {
        var existing = new SharedScript("calc", "return 42;");
        var incoming = new SharedScriptDto("calc", "return 42;", existing.ParameterDefinitions, existing.ReturnDefinition);

        var item = _diff.CompareSharedScript(incoming, existing);

        Assert.Equal(ConflictKind.Identical, item.Kind);
        Assert.Null(item.FieldDiffJson);
    }

    [Fact]
    public void ApiMethod_ModifiedScript_EmitsStructuredLineDiff()
    {
        var existing = new ApiMethod("doThing", "log(\"a\");") { TimeoutSeconds = 30 };
        var incoming = new ApiMethodDto(
            Name: "doThing",
            Script: "log(\"a\");\nlog(\"b\");",
            ParameterDefinitions: existing.ParameterDefinitions,
            ReturnDefinition: existing.ReturnDefinition,
            TimeoutSeconds: 30);

        var item = _diff.CompareApiMethod(incoming, existing);

        Assert.Equal(ConflictKind.Modified, item.Kind);
        var change = ChangeFor(item, "Script");
        var lineDiff = change.GetProperty("lineDiff");
        Assert.Equal(1, lineDiff.GetProperty("addedCount").GetInt32());
        Assert.Equal(0, lineDiff.GetProperty("removedCount").GetInt32());

        var hunks = Hunks(change);
        Assert.Contains(("context", "log(\"a\");"), hunks);
        Assert.Contains(("add", "log(\"b\");"), hunks);
    }

    [Fact]
    public void TemplateScript_ModifiedCode_EmitsStructuredLineDiff()
    {
        var existing = MakeTemplate("T1");
        existing.Scripts.Add(new TemplateScript("onScan", "old1\nold2"));

        var incoming = MakeTemplateDto("T1", scripts:
        [
            new TemplateScriptDto("onScan", "old1\nnew2", null, null, null, null, false, null),
        ]);

        var item = _diff.CompareTemplate(incoming, existing);

        Assert.Equal(ConflictKind.Modified, item.Kind);
        var change = ChangeFor(item, "Scripts.onScan");
        var hunks = Hunks(change);
        Assert.Contains(("context", "old1"), hunks);
        Assert.Contains(("remove", "old2"), hunks);
        Assert.Contains(("add", "new2"), hunks);
    }

    // ============ #05-T23: placeholder-identity resolution via name maps ============

    [Fact]
    public void CompareTemplate_MatchingFolderBaseAndComposition_IsIdentical()
    {
        // A structured template (FolderId, ParentTemplateId, one composition) that
        // the incoming bundle matches by NAME must classify Identical. Before T23,
        // FolderNameOf/BaseTemplateNameOf/CompositionTargetNameOf returned "<id:N>"
        // placeholders that never equalled the incoming names, so every re-import
        // of an unchanged structured template spuriously read Modified.
        var existing = MakeTemplate("Pump");
        existing.FolderId = 5;
        existing.ParentTemplateId = 7;
        existing.Compositions.Add(new TemplateComposition("Mod1") { ComposedTemplateId = 9 });

        var folderNameById = new Dictionary<int, string> { [5] = "Machines" };
        var templateNameById = new Dictionary<int, string> { [7] = "BasePump", [9] = "FeatureX" };

        var incoming = MakeTemplateDto("Pump") with
        {
            FolderName = "Machines",
            BaseTemplateName = "BasePump",
            Compositions = new[] { new TemplateCompositionDto("Mod1", "FeatureX") },
        };

        var item = _diff.CompareTemplate(incoming, existing, folderNameById, templateNameById);

        Assert.Equal(ConflictKind.Identical, item.Kind);
    }

    [Fact]
    public void CompareTemplate_DivergentBaseTemplateName_IsModified()
    {
        // Sanity: the maps must not mask a REAL change. Existing base = "BasePump",
        // incoming names a different base → Modified.
        var existing = MakeTemplate("Pump");
        existing.ParentTemplateId = 7;
        var templateNameById = new Dictionary<int, string> { [7] = "BasePump" };

        var incoming = MakeTemplateDto("Pump") with { BaseTemplateName = "DifferentBase" };

        var item = _diff.CompareTemplate(incoming, existing, folderNameById: null, templateNameById: templateNameById);

        Assert.Equal(ConflictKind.Modified, item.Kind);
    }

    // ============ #05-T6: single-source child equality — diff sees the full field set ============

    [Fact]
    public void CompareTemplate_AttributeElementDataTypeChange_IsModified()
    {
        var existing = MakeTemplate("T1");
        existing.Attributes.Add(new TemplateAttribute("L")
        {
            DataType = DataType.List,
            ElementDataType = DataType.Int32,
            Value = "[1,2]",
        });
        var incoming = MakeTemplateDto("T1", attributes:
        [
            new TemplateAttributeDto("L", "[1,2]", DataType.List, false, null, null, DataType.String),
        ]);

        var item = _diff.CompareTemplate(incoming, existing);

        Assert.Equal(ConflictKind.Modified, item.Kind);
        ChangeFor(item, "Attributes.L"); // ElementDataType diverged — previously missed.
    }

    [Fact]
    public void CompareTemplate_LockedInDerivedChange_IsModified()
    {
        var existing = MakeTemplate("T1");
        existing.Attributes.Add(new TemplateAttribute("L")
        {
            DataType = DataType.Int32,
            Value = "1",
            LockedInDerived = false,
        });
        var incoming = MakeTemplateDto("T1", attributes:
        [
            new TemplateAttributeDto("L", "1", DataType.Int32, false, null, null, null, LockedInDerived: true),
        ]);

        var item = _diff.CompareTemplate(incoming, existing);

        Assert.Equal(ConflictKind.Modified, item.Kind);
        ChangeFor(item, "Attributes.L"); // LockedInDerived diverged — previously missed.
    }

    [Fact]
    public void CompareTemplate_ScriptExecutionTimeoutChange_IsModified()
    {
        var existing = MakeTemplate("T1");
        existing.Scripts.Add(new TemplateScript("S", "return 1;") { ExecutionTimeoutSeconds = 30 });
        var incoming = MakeTemplateDto("T1", scripts:
        [
            // identical code; only ExecutionTimeoutSeconds differs.
            new TemplateScriptDto("S", "return 1;", null, null, null, null, false, null, ExecutionTimeoutSeconds: 60),
        ]);

        var item = _diff.CompareTemplate(incoming, existing);

        Assert.Equal(ConflictKind.Modified, item.Kind);
        ChangeFor(item, "Scripts.S"); // ExecutionTimeoutSeconds diverged — previously missed.
    }

    [Fact]
    public void CompareTemplate_AlarmOnTriggerScriptChange_IsModified()
    {
        var existing = MakeTemplate("T1");
        existing.Scripts.Add(new TemplateScript("Run", "return 1;") { Id = 1 });
        existing.Alarms.Add(new TemplateAlarm("A")
        {
            TriggerType = AlarmTriggerType.RangeViolation,
            OnTriggerScriptId = 1, // resolves to "Run"
        });
        var incoming = MakeTemplateDto("T1",
            scripts: [new TemplateScriptDto("Run", "return 1;", null, null, null, null, false, null)],
            alarms:
            [
                // same alarm fields but no on-trigger script (was "Run").
                new TemplateAlarmDto("A", null, 0, AlarmTriggerType.RangeViolation, null, false, OnTriggerScriptName: null),
            ]);

        var item = _diff.CompareTemplate(incoming, existing);

        Assert.Equal(ConflictKind.Modified, item.Kind);
        ChangeFor(item, "Alarms.A"); // OnTriggerScriptName diverged — previously missed.
    }

    // ============ M8: CompareSite ============

    [Fact]
    public void CompareSite_ExistingNull_New()
    {
        var dto = new SiteDto("site-a", "Site A", null, null, null, null, null);
        var item = _diff.CompareSite(dto, existing: null);

        Assert.Equal(ConflictKind.New, item.Kind);
        Assert.Equal("Site", item.EntityType);
        Assert.Equal("site-a", item.Name);
        Assert.Null(item.FieldDiffJson);
    }

    [Fact]
    public void CompareSite_FieldDiffers_Modified()
    {
        var existing = new Site("Site A", "site-a") { Description = "old", NodeAAddress = "10.0.0.1" };
        var dto = new SiteDto("site-a", "Site A", "new", "10.0.0.1", null, null, null);

        var item = _diff.CompareSite(dto, existing);

        Assert.Equal(ConflictKind.Modified, item.Kind);
        var change = ChangeFor(item, "Description");
        Assert.Equal("old", change.GetProperty("oldValue").GetString());
        Assert.Equal("new", change.GetProperty("newValue").GetString());
    }

    [Fact]
    public void CompareSite_NoChanges_Identical()
    {
        var existing = new Site("Site A", "site-a")
        {
            Description = "d",
            NodeAAddress = "a",
            NodeBAddress = "b",
            GrpcNodeAAddress = "ga",
            GrpcNodeBAddress = "gb",
        };
        var dto = new SiteDto("site-a", "Site A", "d", "a", "b", "ga", "gb");

        var item = _diff.CompareSite(dto, existing);

        Assert.Equal(ConflictKind.Identical, item.Kind);
        Assert.Null(item.FieldDiffJson);
    }

    // ============ M8: CompareDataConnection ============

    [Fact]
    public void CompareDataConnection_ExistingNull_New()
    {
        var dto = new DataConnectionDto("site-a", "opc1", "OpcUa", 3, null);
        var item = _diff.CompareDataConnection(dto, existing: null);

        Assert.Equal(ConflictKind.New, item.Kind);
        Assert.Equal("DataConnection", item.EntityType);
        Assert.Equal("opc1", item.Name);
    }

    [Fact]
    public void CompareDataConnection_ProtocolDiffers_Modified()
    {
        var existing = new DataConnection("opc1", "OpcUa", siteId: 1) { FailoverRetryCount = 3 };
        var dto = new DataConnectionDto("site-a", "opc1", "MxAccess", 3, null);

        var item = _diff.CompareDataConnection(dto, existing);

        Assert.Equal(ConflictKind.Modified, item.Kind);
        var change = ChangeFor(item, "Protocol");
        Assert.Equal("OpcUa", change.GetProperty("oldValue").GetString());
        Assert.Equal("MxAccess", change.GetProperty("newValue").GetString());
    }

    [Fact]
    public void CompareDataConnection_SecretValueChangesButPresencePreserved_NoSecretEcho()
    {
        // Both sides HAVE a primary configuration secret; only the value differs.
        // Presence-only comparison => no Secrets.* change, and the value is never echoed.
        var existing = new DataConnection("opc1", "OpcUa", siteId: 1)
        {
            FailoverRetryCount = 3,
            PrimaryConfiguration = "{\"endpoint\":\"opc.tcp://OLD:4840\"}",
        };
        var dto = new DataConnectionDto("site-a", "opc1", "OpcUa", 3,
            new SecretsBlock(new Dictionary<string, string>
            {
                ["PrimaryConfiguration"] = "{\"endpoint\":\"opc.tcp://NEW:4840\"}",
            }));

        var item = _diff.CompareDataConnection(dto, existing);

        Assert.Equal(ConflictKind.Identical, item.Kind);
        Assert.Null(item.FieldDiffJson);
        // The secret value must never appear anywhere in the diff output.
        Assert.DoesNotContain("4840", item.FieldDiffJson ?? string.Empty);
    }

    [Fact]
    public void CompareDataConnection_SecretPresenceFlips_ShowsPresentMarkerOnly()
    {
        // Existing has a primary config; incoming carries no secret => presence change.
        var existing = new DataConnection("opc1", "OpcUa", siteId: 1)
        {
            FailoverRetryCount = 3,
            PrimaryConfiguration = "{\"endpoint\":\"opc.tcp://h:4840\"}",
        };
        var dto = new DataConnectionDto("site-a", "opc1", "OpcUa", 3, Secrets: null);

        var item = _diff.CompareDataConnection(dto, existing);

        Assert.Equal(ConflictKind.Modified, item.Kind);
        var change = ChangeFor(item, "Secrets.PrimaryConfiguration");
        Assert.Equal("<present>", change.GetProperty("oldValue").GetString());
        // newValue is null and omitted from JSON by the WhenWritingNull policy.
        Assert.False(change.TryGetProperty("newValue", out _));
        Assert.DoesNotContain("4840", item.FieldDiffJson!);
    }

    // ============ SMS: CompareSmsConfiguration (S10b) ============

    private static SmsConfiguration ExistingSms() =>
        new("AC1", "+15550000000") { Id = 1, AuthToken = "stored-token" };

    private static SmsConfigDto SmsDto(
        string from = "+15550000000",
        string? msgSid = null,
        bool withSecret = true) =>
        new("AC1", from, msgSid, ApiBaseUrl: null, ConnectionTimeoutSeconds: 30,
            MaxRetries: 10, RetryDelay: TimeSpan.FromMinutes(1),
            Secrets: withSecret
                ? new SecretsBlock(new Dictionary<string, string> { ["AuthToken"] = "wire-token" })
                : null);

    [Fact]
    public void CompareSmsConfiguration_ExistingNull_New()
    {
        var item = _diff.CompareSmsConfiguration(SmsDto(), existing: null);

        Assert.Equal(ConflictKind.New, item.Kind);
        Assert.Equal("SmsConfiguration", item.EntityType);
        Assert.Equal("AC1", item.Name);
    }

    [Fact]
    public void CompareSmsConfiguration_AllFieldsAndPresenceMatch_Identical()
    {
        var item = _diff.CompareSmsConfiguration(SmsDto(), ExistingSms());

        Assert.Equal(ConflictKind.Identical, item.Kind);
        Assert.Null(item.FieldDiffJson);
    }

    [Fact]
    public void CompareSmsConfiguration_FromNumberDiffers_Modified()
    {
        var item = _diff.CompareSmsConfiguration(SmsDto(from: "+15559999999"), ExistingSms());

        Assert.Equal(ConflictKind.Modified, item.Kind);
        var change = ChangeFor(item, "FromNumber");
        Assert.Equal("+15550000000", change.GetProperty("oldValue").GetString());
        Assert.Equal("+15559999999", change.GetProperty("newValue").GetString());
    }

    [Fact]
    public void CompareSmsConfiguration_AuthTokenValueChangesButPresencePreserved_NoSecretEcho()
    {
        // Both sides carry a token; only the value differs. Presence-only comparison =>
        // no Secrets.AuthToken change, and neither token value is ever echoed.
        var item = _diff.CompareSmsConfiguration(SmsDto(withSecret: true), ExistingSms());

        Assert.Equal(ConflictKind.Identical, item.Kind);
        var json = item.FieldDiffJson ?? string.Empty;
        Assert.DoesNotContain("stored-token", json);
        Assert.DoesNotContain("wire-token", json);
    }

    [Fact]
    public void CompareSmsConfiguration_AuthTokenPresenceFlips_ShowsPresentMarkerOnly()
    {
        // Existing has a token; incoming carries no secret => a presence change that
        // surfaces only the "<present>" marker, never the token value.
        var item = _diff.CompareSmsConfiguration(SmsDto(withSecret: false), ExistingSms());

        Assert.Equal(ConflictKind.Modified, item.Kind);
        var change = ChangeFor(item, "Secrets.AuthToken");
        Assert.Equal("<present>", change.GetProperty("oldValue").GetString());
        Assert.False(change.TryGetProperty("newValue", out _));
        Assert.DoesNotContain("stored-token", item.FieldDiffJson!);
    }

    // ============ M8: CompareInstance ============

    [Fact]
    public void CompareInstance_ExistingNull_New()
    {
        var dto = MakeInstanceDto("inst-1");
        var item = _diff.CompareInstance(dto, existing: null);

        Assert.Equal(ConflictKind.New, item.Kind);
        Assert.Equal("Instance", item.EntityType);
        Assert.Equal("inst-1", item.Name);
    }

    [Fact]
    public void CompareInstance_StateDiffers_Modified()
    {
        var existing = new Instance("inst-1") { State = InstanceState.Disabled };
        var dto = MakeInstanceDto("inst-1", state: InstanceState.Enabled);

        var item = _diff.CompareInstance(dto, existing);

        Assert.Equal(ConflictKind.Modified, item.Kind);
        var change = ChangeFor(item, "State");
        Assert.Equal("Disabled", change.GetProperty("oldValue").GetString());
        Assert.Equal("Enabled", change.GetProperty("newValue").GetString());
    }

    [Fact]
    public void CompareInstance_NoChanges_Identical()
    {
        var existing = new Instance("inst-1") { State = InstanceState.Enabled };
        var dto = MakeInstanceDto("inst-1", state: InstanceState.Enabled);

        var item = _diff.CompareInstance(dto, existing);

        Assert.Equal(ConflictKind.Identical, item.Kind);
        Assert.Null(item.FieldDiffJson);
    }

    [Fact]
    public void CompareInstance_TemplateAndSiteNamesDiffer_Modified()
    {
        var existing = new Instance("inst-1") { State = InstanceState.Enabled };
        var dto = MakeInstanceDto("inst-1", template: "TmplB", site: "site-b", state: InstanceState.Enabled);

        var item = _diff.CompareInstance(dto, existing,
            existingTemplateName: "TmplA", existingSiteIdentifier: "site-a");

        Assert.Equal(ConflictKind.Modified, item.Kind);
        Assert.Equal("TmplA", ChangeFor(item, "TemplateName").GetProperty("oldValue").GetString());
        Assert.Equal("TmplB", ChangeFor(item, "TemplateName").GetProperty("newValue").GetString());
        Assert.Equal("site-a", ChangeFor(item, "SiteIdentifier").GetProperty("oldValue").GetString());
        Assert.Equal("site-b", ChangeFor(item, "SiteIdentifier").GetProperty("newValue").GetString());
    }

    [Fact]
    public void CompareInstance_ChildOverridesAddedRemovedModified()
    {
        var existing = new Instance("inst-1") { State = InstanceState.Enabled };
        // Will be REMOVED (present existing, absent incoming).
        existing.AttributeOverrides.Add(new InstanceAttributeOverride("Setpoint") { OverrideValue = "10" });
        // Will be MODIFIED (present both, value differs).
        existing.AttributeOverrides.Add(new InstanceAttributeOverride("Scale") { OverrideValue = "1.0" });

        var dto = MakeInstanceDto("inst-1", state: InstanceState.Enabled, attributeOverrides:
        [
            new InstanceAttributeOverrideDto("Scale", "2.0", null),   // modified
            new InstanceAttributeOverrideDto("Offset", "5", null),    // added
        ]);

        var item = _diff.CompareInstance(dto, existing);

        Assert.Equal(ConflictKind.Modified, item.Kind);

        var removed = ChangeFor(item, "AttributeOverrides.Setpoint");
        Assert.Equal("<present>", removed.GetProperty("oldValue").GetString());
        Assert.False(removed.TryGetProperty("newValue", out _));

        var added = ChangeFor(item, "AttributeOverrides.Offset");
        Assert.False(added.TryGetProperty("oldValue", out _));
        Assert.Equal("<added>", added.GetProperty("newValue").GetString());

        var modified = ChangeFor(item, "AttributeOverrides.Scale");
        Assert.Equal("<modified>", modified.GetProperty("oldValue").GetString());
        Assert.Equal("<modified>", modified.GetProperty("newValue").GetString());
    }

    // ---- builders ----

    private static Commons.Entities.Templates.Template MakeTemplate(string name) =>
        new(name);

    private static TemplateDto MakeTemplateDto(
        string name,
        IReadOnlyList<TemplateScriptDto>? scripts = null,
        IReadOnlyList<TemplateAttributeDto>? attributes = null,
        IReadOnlyList<TemplateAlarmDto>? alarms = null) =>
        new(
            Name: name,
            FolderName: null,
            BaseTemplateName: null,
            Description: null,
            Attributes: attributes ?? Array.Empty<TemplateAttributeDto>(),
            Alarms: alarms ?? Array.Empty<TemplateAlarmDto>(),
            Scripts: scripts ?? Array.Empty<TemplateScriptDto>(),
            Compositions: Array.Empty<TemplateCompositionDto>());

    private static InstanceDto MakeInstanceDto(
        string uniqueName,
        string template = "Tmpl",
        string site = "site-a",
        InstanceState state = InstanceState.Enabled,
        IReadOnlyList<InstanceAttributeOverrideDto>? attributeOverrides = null) =>
        new(
            UniqueName: uniqueName,
            TemplateName: template,
            SiteIdentifier: site,
            AreaName: null,
            State: state,
            AttributeOverrides: attributeOverrides ?? Array.Empty<InstanceAttributeOverrideDto>(),
            AlarmOverrides: Array.Empty<InstanceAlarmOverrideDto>(),
            NativeAlarmSourceOverrides: Array.Empty<InstanceNativeAlarmSourceOverrideDto>(),
            ConnectionBindings: Array.Empty<InstanceConnectionBindingDto>());
}
