using System.CommandLine;
using System.CommandLine.Parsing;
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Management;

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

/// <summary>
/// The <c>scadabridge audit-config</c> command group: views the configuration-change
/// audit log (the <c>IAuditService</c> trail of admin edits — distinct from the
/// centralized append-only Audit Log served by <see cref="AuditCommands"/>).
/// </summary>
/// <remarks>
/// Renamed from <c>audit-log</c> to avoid confusion with the new
/// <c>scadabridge audit</c> group. The old <c>audit-log</c> name is retained as a
/// deprecated alias; <see cref="DeprecatedAlias"/> still resolves the full subcommand
/// tree, and <c>Program.cs</c> prints a deprecation warning when it is used.
/// </remarks>
public static class AuditLogCommands
{
    /// <summary>The deprecated alias kept for backward compatibility with the old command name.</summary>
    public const string DeprecatedAlias = "audit-log";

    /// <summary>The deprecation warning emitted when the old <c>audit-log</c> name is used.</summary>
    public const string DeprecationWarning =
        "Warning: 'audit-log' is deprecated and will be removed in a future release. "
        + "Use 'audit-config' instead.";

    /// <summary>
    /// Writes the <see cref="DeprecationWarning"/> to <paramref name="stderr"/> when the
    /// CLI was invoked via the deprecated <c>audit-log</c> command name (i.e. the first
    /// argument is <see cref="DeprecatedAlias"/>). The command itself still works — it is
    /// an alias of <c>audit-config</c> — so this only adds the migration warning.
    /// Factored out of <c>Program.cs</c> so it is unit-testable without spawning a process.
    /// </summary>
    /// <param name="args">The raw command-line arguments passed to the CLI.</param>
    /// <param name="stderr">The text writer to emit the deprecation warning to.</param>
    public static void WriteDeprecationWarningIfNeeded(string[] args, TextWriter stderr)
    {
        if (args.Length > 0
            && string.Equals(args[0], DeprecatedAlias, StringComparison.Ordinal))
        {
            stderr.WriteLine(DeprecationWarning);
        }
    }

    /// <summary>
    /// Builds the <c>audit-config</c> command (with the deprecated <c>audit-log</c> alias) and its subcommands.
    /// </summary>
    /// <param name="urlOption">Global management URL option.</param>
    /// <param name="formatOption">Global output format option.</param>
    /// <param name="usernameOption">Global username option.</param>
    /// <param name="passwordOption">Global password option.</param>
    /// <returns>The configured <c>audit-config</c> command with all sub-commands registered.</returns>
    public static Command Build(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
    {
        var command = new Command("audit-config") { Description = "Query the configuration-change audit log" };
        // Backward-compatible alias for the old `audit-log` name. The alias keeps
        // full subcommand parity automatically; the deprecation warning is emitted by
        // the args[0] check in Program.cs.
        command.Aliases.Add(DeprecatedAlias);

        command.Add(BuildQuery(urlOption, formatOption, usernameOption, passwordOption));

        return command;
    }

    private static Command BuildQuery(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
    {
        var userOption = new Option<string?>("--user") { Description = "Filter by username" };
        var entityTypeOption = new Option<string?>("--entity-type") { Description = "Filter by entity type" };
        var actionOption = new Option<string?>("--action") { Description = "Filter by action" };
        var fromOption = new Option<DateTimeOffset?>("--from") { Description = "Start date (ISO 8601)" };
        var toOption = new Option<DateTimeOffset?>("--to") { Description = "End date (ISO 8601)" };
        var pageOption = new Option<int>("--page") { Description = "Page number" };
        pageOption.DefaultValueFactory = _ => 1;
        var pageSizeOption = new Option<int>("--page-size") { Description = "Page size" };
        pageSizeOption.DefaultValueFactory = _ => 50;

        var cmd = new Command("query") { Description = "Query audit log entries" };
        cmd.Add(userOption);
        cmd.Add(entityTypeOption);
        cmd.Add(actionOption);
        cmd.Add(fromOption);
        cmd.Add(toOption);
        cmd.Add(pageOption);
        cmd.Add(pageSizeOption);
        cmd.SetAction(async (ParseResult result) =>
        {
            var user = result.GetValue(userOption);
            var entityType = result.GetValue(entityTypeOption);
            var action = result.GetValue(actionOption);
            var from = result.GetValue(fromOption);
            var to = result.GetValue(toOption);
            var page = result.GetValue(pageOption);
            var pageSize = result.GetValue(pageSizeOption);
            return await CommandHelpers.ExecuteCommandAsync(
                result, urlOption, formatOption, usernameOption, passwordOption,
                new QueryAuditLogCommand(user, entityType, action, from, to, page, pageSize));
        });
        return cmd;
    }
}
