using Shouldly;
using Xunit;

namespace ZB.MOM.WW.OtOpcUa.Driver.S7.Cli.Tests;

/// <summary>
///     Driver.S7.Cli-011: the <c>subscribe</c> command's <c>OnDataChange</c> handler must
///     serialize its console writes through a lock so that overlapping poll ticks (which
///     arrive on a background thread) cannot interleave partial lines on the output stream.
///     Mirrors the pattern from the Modbus CLI subscribe command.
/// </summary>
[Trait("Category", "Unit")]
public sealed class SubscribeCommandWriteLockTests
{
    private static readonly string CommandsDir = LocateCommandsDir();

    /// <summary>
    ///     Verifies that SubscribeCommand uses a lock in the OnDataChange handler to
    ///     prevent interleaved console writes from overlapping poll ticks.
    /// </summary>
    [Fact]
    public void SubscribeCommand_OnDataChange_uses_write_lock()
    {
        // Driver.S7.Cli-011: the handler writes via console.Output.WriteLine on a
        // background poll thread; concurrent ticks must be serialised with a lock
        // to prevent partial-line interleaving.
        var source = File.ReadAllText(Path.Combine(CommandsDir, "SubscribeCommand.cs"));
        source.ShouldContain("lock (writeLock)");
    }

    private static string LocateCommandsDir()
    {
        var dir = new DirectoryInfo(AppContext.BaseDirectory);
        while (dir is not null && !File.Exists(Path.Combine(dir.FullName, "ZB.MOM.WW.OtOpcUa.slnx")))
            dir = dir.Parent;
        dir.ShouldNotBeNull("Could not find solution root (ZB.MOM.WW.OtOpcUa.slnx).");
        return Path.Combine(
            dir!.FullName, "src", "Drivers", "Cli", "ZB.MOM.WW.OtOpcUa.Driver.S7.Cli", "Commands");
    }
}
