using System.CommandLine;
using ZB.MOM.WW.ScadaBridge.CLI.Commands;

namespace ZB.MOM.WW.ScadaBridge.CLI.Tests.Commands;

/// <summary>
/// Tests for the <c>audit-log</c> → <c>audit-config</c> rename (Audit Log #23 M8-T7):
/// the new name parses, the deprecated <c>audit-log</c> alias still resolves the full
/// subcommand tree and emits a stderr deprecation warning, and the renamed group does
/// not collide with the distinct <c>audit</c> group from Bundle A.
/// </summary>
public class AuditConfigDeprecationTests
{
    private static readonly Option<string> Url = new("--url") { Recursive = true };
    private static readonly Option<string> Username = new("--username") { Recursive = true };
    private static readonly Option<string> Password = new("--password") { Recursive = true };
    private static readonly Option<string> Format = CliOptions.CreateFormatOption();

    private static RootCommand BuildRoot()
    {
        var root = new RootCommand();
        root.Add(Url);
        root.Add(Username);
        root.Add(Password);
        root.Add(Format);
        root.Add(AuditCommands.Build(Url, Format, Username, Password));
        root.Add(AuditLogCommands.Build(Url, Format, Username, Password));
        return root;
    }

    [Fact]
    public void AuditConfig_Query_Works()
    {
        // The new `audit-config query` name parses cleanly with no errors.
        var root = BuildRoot();
        var parse = root.Parse(new[] { "audit-config", "query", "--user", "alice" });
        Assert.Empty(parse.Errors);
    }

    [Fact]
    public void AuditLog_Query_StillWorks_ButEmitsDeprecationWarning_ToStderr()
    {
        // The deprecated `audit-log` alias still resolves the full subcommand tree...
        var root = BuildRoot();
        var parse = root.Parse(new[] { "audit-log", "query", "--user", "alice" });
        Assert.Empty(parse.Errors);

        // ...and invoking via the old name emits the deprecation warning to stderr.
        var stderr = new StringWriter();
        AuditLogCommands.WriteDeprecationWarningIfNeeded(
            new[] { "audit-log", "query" }, stderr);
        var warning = stderr.ToString();
        Assert.Contains("deprecated", warning);
        Assert.Contains("audit-config", warning);
    }

    [Fact]
    public void DeprecationWarning_NotEmitted_ForNewName()
    {
        // The new `audit-config` name must not trigger the deprecation warning.
        var stderr = new StringWriter();
        AuditLogCommands.WriteDeprecationWarningIfNeeded(
            new[] { "audit-config", "query" }, stderr);
        Assert.Equal("", stderr.ToString());
    }

    [Fact]
    public void DeprecationWarning_NotEmitted_ForUnrelatedCommand()
    {
        var stderr = new StringWriter();
        AuditLogCommands.WriteDeprecationWarningIfNeeded(
            new[] { "audit", "query" }, stderr);
        Assert.Equal("", stderr.ToString());
    }

    [Fact]
    public void Audit_And_AuditConfig_AreDistinctCommands_NoConflict()
    {
        var root = BuildRoot();

        var auditNames = new[] { "audit", "audit-config" };
        foreach (var name in auditNames)
        {
            var match = root.Subcommands.SingleOrDefault(c => c.Name == name);
            Assert.NotNull(match);
        }

        // The two groups are distinct objects with distinct subcommand sets:
        // `audit` has query/export/verify-chain; `audit-config` has only query.
        var audit = root.Subcommands.Single(c => c.Name == "audit");
        var auditConfig = root.Subcommands.Single(c => c.Name == "audit-config");
        Assert.NotSame(audit, auditConfig);
        Assert.Contains(audit.Subcommands, c => c.Name == "verify-chain");
        Assert.DoesNotContain(auditConfig.Subcommands, c => c.Name == "verify-chain");

        // `audit-config` carries the deprecated `audit-log` alias; `audit` does not.
        Assert.Contains(AuditLogCommands.DeprecatedAlias, auditConfig.Aliases);
        Assert.DoesNotContain(AuditLogCommands.DeprecatedAlias, audit.Aliases);
    }
}
