using Shouldly;
using Xunit;

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

/// <summary>
///     Driver.S7.Cli-010: the long-running <c>subscribe</c> command must call
///     <c>FlushLogging()</c> in its <c>finally</c> block so buffered Serilog log lines
///     emitted just before Ctrl+C are not discarded on process exit.
///     <para>
///         <c>DriverCommandBase.ConfigureLogging()</c> instructs every command to call
///         <c>FlushLogging()</c> in a <c>finally</c>. The short-lived <c>read</c>,
///         <c>write</c>, and <c>probe</c> commands are less exposed (their log volume is
///         small and the process exits immediately after), but <c>subscribe</c> can run for
///         minutes and then Ctrl+C — making the flush critical.
///     </para>
/// </summary>
[Trait("Category", "Unit")]
public sealed class FlushLoggingConventionTests
{
    private static readonly string CommandsDir = LocateCommandsDir();

    /// <summary>
    ///     Verifies that SubscribeCommand calls FlushLogging() to prevent buffered
    ///     Serilog output from being lost on Ctrl+C.
    /// </summary>
    [Fact]
    public void SubscribeCommand_calls_FlushLogging()
    {
        // Driver.S7.Cli-010: FlushLogging() must appear in the command so that
        // DriverCommandBase.ConfigureLogging()'s documented contract is honoured.
        var source = File.ReadAllText(Path.Combine(CommandsDir, "SubscribeCommand.cs"));
        source.ShouldContain("FlushLogging()");
    }

    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");
    }
}
