using Spectre.Console.Testing;
using ZB.MOM.WW.Secrets.Cli.Interactive;

namespace ZB.MOM.WW.Secrets.Tests.Cli.Interactive;

/// <summary>
/// Pins the composition root of the interactive console: the non-TTY gate that decides whether a bare
/// <c>secret</c> invocation launches the console, and the exact flow set (order + uniqueness) the shell
/// is wired with. These are the two things Program.cs delegates to, so they are asserted here directly
/// rather than by driving the whole shell.
/// </summary>
public sealed class InteractiveEntryTests
{
    [Theory]
    // Only a bare invocation on a real TTY (neither stream redirected) enters the interactive console.
    [InlineData(new string[0], false, false, true)]
    [InlineData(new string[0], true, false, false)]
    [InlineData(new string[0], false, true, false)]
    [InlineData(new string[0], true, true, false)]
    [InlineData(new[] { "list" }, false, false, false)]
    public void ShouldEnterInteractive_true_only_for_no_args_and_real_tty(
        string[] args, bool inputRedirected, bool outputRedirected, bool expected)
    {
        Assert.Equal(
            expected,
            InteractiveEntry.ShouldEnterInteractive(args, inputRedirected, outputRedirected));
    }

    [Fact]
    public void CreateShell_composes_all_flows_exactly_once()
    {
        // CreateShell must succeed — its InteractiveShell ctor re-validates flow-title uniqueness, so a
        // duplicate or reserved collision would throw here.
        InteractiveShell shell = InteractiveEntry.CreateShell(new TestConsole());
        Assert.NotNull(shell);

        // The composed flow set is asserted through the same seam CreateShell uses.
        string[] titles = InteractiveEntry.CreateFlows().Select(f => f.Title).ToArray();

        Assert.Equal(
            new[]
            {
                "List secrets",
                "Set / rotate a secret",
                "Get (reveal) a secret",
                "Delete a secret",
                "Reference audit & seed",
                "KEK doctor (lockout recovery)",
                "Export bundle (ciphertext-only)",
                "Import bundle",
            },
            titles);

        // Each title appears exactly once.
        Assert.Equal(titles.Length, titles.Distinct(StringComparer.Ordinal).Count());
    }
}
