using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
using ZB.MOM.WW.OtOpcUa.Driver.TwinCAT;

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

/// <summary>
///     CONV-4 — <see cref="TwinCATDriver.ResolveHost"/> must resolve an authored raw tag to its OWN
///     device host so per-host breaker keys are correct for equipment tags, not the first-device
///     fallback. Under v3 the tag is delivered as a <see cref="RawTagEntry"/> whose
///     <see cref="RawTagEntry.DeviceName"/> names the owning device; the driver threads that onto the
///     def's host at Initialize, and ResolveHost reads it back by RawPath.
/// </summary>
[Trait("Category", "Unit")]
public sealed class TwinCATResolveHostTests
{
    private const string DeviceA = "ads://5.23.91.23.1.1:851";
    private const string DeviceB = "ads://5.23.91.23.1.2:851";

    private static async Task<TwinCATDriver> NewDriverAsync(params RawTagEntry[] rawTags)
    {
        var drv = new TwinCATDriver(
            new TwinCATDriverOptions
            {
                Devices = [new TwinCATDeviceOptions(DeviceA), new TwinCATDeviceOptions(DeviceB)],
                RawTags = rawTags,
                Probe = new TwinCATProbeOptions { Enabled = false },
                EnableControllerBrowse = false,
            },
            "twincat-1", new FakeTwinCATClientFactory());
        await drv.InitializeAsync("{}", CancellationToken.None);
        return drv;
    }

    /// <summary>A raw tag naming device B resolves to device B's host, not the first device.</summary>
    [Fact]
    public async Task ResolveHost_RawTagOnDeviceB_ReturnsItsOwnDeviceHost()
    {
        var blob = """{"symbolPath":"MAIN.Speed","dataType":"DInt"}""";
        var drv = await NewDriverAsync(new RawTagEntry("equip/Speed", blob, WriteIdempotent: false, DeviceName: DeviceB));
        drv.ResolveHost("equip/Speed").ShouldBe(DeviceB);
    }

    /// <summary>An unresolvable ref keeps the current first-device fallback.</summary>
    [Fact]
    public async Task ResolveHost_UnknownRef_KeepsCurrentFallback()
    {
        var drv = await NewDriverAsync();
        drv.ResolveHost("totally-unknown").ShouldBe(DeviceA);
    }
}
