using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ArchestrA.GRAccess;
using CliFx;
using CliFx.Attributes;
using CliFx.Infrastructure;
using ZB.MOM.WW.GRAccess.Cli.GRAccess;
using ZB.MOM.WW.GRAccess.Cli.Infrastructure;

namespace ZB.MOM.WW.GRAccess.Cli.Commands
{
    public abstract class RoutedCommandBase : ICommand
    {
        [CommandOption("galaxy", 'g', Description = "Galaxy name", IsRequired = true)]
        public string GalaxyName { get; init; }

        [CommandOption("node", 'n', Description = "GR node name. Required for one-shot mode; ignored when a session is active.")]
        public string NodeName { get; init; } = "";

        [CommandOption("json", Description = "Output as JSON")]
        public bool Json { get; init; }

        [CommandOption("llm-json", Description = "Output stable machine JSON envelope")]
        public bool LlmJson { get; init; }

        public abstract string Command { get; }
        public abstract string Subcommand { get; }

        public virtual Dictionary<string, object> Args() => new Dictionary<string, object>
        {
            ["json"] = Json,
            ["llm-json"] = LlmJson
        };

        public async ValueTask ExecuteAsync(IConsole console)
        {
            var args = Args();
            await CommandRouter.ExecuteAsync(
                    console,
                    GalaxyName,
                    NodeName,
                    Command,
                    Subcommand,
                    args,
                    galaxy => GRAccessCommandDispatcher.Execute(galaxy, Command, Subcommand, args))
                .ConfigureAwait(false);
        }
    }

    public abstract class ConfirmedRoutedCommandBase : RoutedCommandBase
    {
        [CommandOption("confirm", Description = "Required for mutating commands")]
        public bool Confirm { get; init; }

        [CommandOption("confirm-target", Description = "Required exact target for mutating/destructive commands")]
        public string ConfirmTarget { get; init; } = "";

        [CommandOption("dry-run", Description = "Validate a mutating command without invoking mutating GRAccess calls")]
        public bool DryRun { get; init; }

        public override Dictionary<string, object> Args()
        {
            var args = base.Args();
            args["confirm"] = Confirm;
            args["confirm-target"] = ConfirmTarget;
            args["dry-run"] = DryRun;
            return args;
        }
    }

    public abstract class ObjectCommandBase : ConfirmedRoutedCommandBase
    {
        [CommandOption("name", Description = "Object tagname", IsRequired = true)]
        public string ObjectName { get; init; }

        [CommandOption("type", 't', Description = "Object type: all, template, instance")]
        public string Type { get; init; } = "all";

        public override Dictionary<string, object> Args()
        {
            var args = base.Args();
            args["name"] = ObjectName;
            args["type"] = Type;
            return args;
        }
    }

    public abstract class BulkObjectsCommandBase : ConfirmedRoutedCommandBase
    {
        [CommandOption("name", Description = "Object tagname. May be repeated.")]
        public IReadOnlyList<string> Names { get; init; } = Array.Empty<string>();

        [CommandOption("pattern", 'p', Description = "GRAccess name pattern. May be repeated. Use % as wildcard.")]
        public IReadOnlyList<string> Patterns { get; init; } = Array.Empty<string>();

        [CommandOption("type", 't', Description = "Object type: all, template, instance")]
        public string Type { get; init; } = "instance";

        public override Dictionary<string, object> Args()
        {
            var args = base.Args();
            args["name"] = Names;
            args["pattern"] = Patterns;
            args["type"] = Type;
            return args;
        }
    }

    [Command("galaxy info", Description = "Show galaxy version and status")]
    public sealed class GalaxyInfoCommand : RoutedCommandBase { public override string Command => "galaxy"; public override string Subcommand => "info"; }

    [Command("galaxy sync", Description = "Synchronize the local client with the galaxy")]
    public sealed class GalaxySyncCommand : RoutedCommandBase { public override string Command => "galaxy"; public override string Subcommand => "sync"; }

    [Command("galaxy cdi-version", Description = "Show galaxy CDI version")]
    public sealed class GalaxyCdiVersionCommand : RoutedCommandBase { public override string Command => "galaxy"; public override string Subcommand => "cdi-version"; }

    [Command("galaxy defaults get", Description = "Get a user default")]
    public sealed class GalaxyDefaultsGetCommand : RoutedCommandBase
    {
        public override string Command => "galaxy";
        public override string Subcommand => "defaults-get";

        [CommandOption("default", Description = "EUserDefault enum name", IsRequired = true)]
        public string Default { get; init; }

        public override Dictionary<string, object> Args() { var args = base.Args(); args["default"] = Default; return args; }
    }

    [Command("galaxy defaults set", Description = "Set a user default")]
    public sealed class GalaxyDefaultsSetCommand : ConfirmedRoutedCommandBase
    {
        public override string Command => "galaxy";
        public override string Subcommand => "defaults-set";

        [CommandOption("default", Description = "EUserDefault enum name", IsRequired = true)]
        public string Default { get; init; }

        [CommandOption("value", Description = "Default value", IsRequired = true)]
        public string Value { get; init; }

        public override Dictionary<string, object> Args() { var args = base.Args(); args["default"] = Default; args["value"] = Value; return args; }
    }

    [Command("galaxy backup", Description = "Back up a galaxy")]
    public sealed class GalaxyBackupCommand : ConfirmedRoutedCommandBase
    {
        public override string Command => "galaxy";
        public override string Subcommand => "backup";

        [CommandOption("file", Description = "Backup file path", IsRequired = true)]
        public string File { get; init; }

        public override Dictionary<string, object> Args() { var args = base.Args(); args["file"] = File; args["node"] = NodeName; return args; }
    }

    [Command("galaxy restore", Description = "Restore a galaxy backup")]
    public sealed class GalaxyRestoreCommand : ConfirmedRoutedCommandBase
    {
        public override string Command => "galaxy";
        public override string Subcommand => "restore";

        [CommandOption("file", Description = "Backup file path", IsRequired = true)]
        public string File { get; init; }

        [CommandOption("restore-older", Description = "Allow restoring an older version")]
        public bool RestoreOlder { get; init; }

        public override Dictionary<string, object> Args() { var args = base.Args(); args["file"] = File; args["node"] = NodeName; args["restore-older"] = RestoreOlder; return args; }
    }

    [Command("galaxy migrate", Description = "Migrate or upgrade a galaxy")]
    public sealed class GalaxyMigrateCommand : ConfirmedRoutedCommandBase { public override string Command => "galaxy"; public override string Subcommand => "migrate"; public override Dictionary<string, object> Args() { var args = base.Args(); args["node"] = NodeName; return args; } }

    [Command("galaxy import-objects", Description = "Import objects from an aaPKG file")]
    public sealed class GalaxyImportObjectsCommand : ConfirmedRoutedCommandBase
    {
        public override string Command => "galaxy";
        public override string Subcommand => "import-objects";

        [CommandOption("file", Description = "Input file path", IsRequired = true)]
        public string File { get; init; }

        [CommandOption("overwrite", Description = "Allow overwrites")]
        public bool Overwrite { get; init; }

        public override Dictionary<string, object> Args() { var args = base.Args(); args["file"] = File; args["overwrite"] = Overwrite; return args; }
    }

    [Command("galaxy import-objects-ex", Description = "Import objects with conflict resolution")]
    public sealed class GalaxyImportObjectsExCommand : ConfirmedRoutedCommandBase
    {
        public override string Command => "galaxy";
        public override string Subcommand => "import-objects-ex";

        [CommandOption("file", Description = "Input file path", IsRequired = true)]
        public string File { get; init; }

        [CommandOption("version-conflict", Description = "E_RESOLVE_VERSION_CONFLICT_ACTION enum value", IsRequired = true)]
        public string VersionConflict { get; init; }

        [CommandOption("name-conflict", Description = "E_RESOLVE_NAME_CONFLICT_ACTION enum value", IsRequired = true)]
        public string NameConflict { get; init; }

        [CommandOption("append-name", Description = "Append suffix for name conflicts")]
        public string AppendName { get; init; } = "";

        public override Dictionary<string, object> Args() { var args = base.Args(); args["file"] = File; args["version-conflict"] = VersionConflict; args["name-conflict"] = NameConflict; args["append-name"] = AppendName; return args; }
    }

    [Command("galaxy import-script-library", Description = "Import a script library")]
    public sealed class GalaxyImportScriptLibraryCommand : ConfirmedRoutedCommandBase
    {
        public override string Command => "galaxy";
        public override string Subcommand => "import-script-library";

        [CommandOption("path", Description = "Script library path", IsRequired = true)]
        public string Path { get; init; }

        public override Dictionary<string, object> Args() { var args = base.Args(); args["path"] = Path; return args; }
    }

    [Command("galaxy export-all", Description = "Export all objects from a galaxy")]
    public sealed class GalaxyExportAllCommand : RoutedCommandBase
    {
        public override string Command => "galaxy";
        public override string Subcommand => "export-all";

        [CommandOption("output", Description = "Output file path", IsRequired = true)]
        public string Output { get; init; }

        [CommandOption("export-type", Description = "EExportType enum value")]
        public string ExportType { get; init; } = "exportGalaxyDump";

        public override Dictionary<string, object> Args() { var args = base.Args(); args["output"] = Output; args["export-type"] = ExportType; return args; }
    }

    [Command("galaxy grload", Description = "Run GRLoad from a CSV file")]
    public sealed class GalaxyGrloadCommand : ConfirmedRoutedCommandBase
    {
        public override string Command => "galaxy";
        public override string Subcommand => "grload";

        [CommandOption("file", Description = "CSV file path", IsRequired = true)]
        public string File { get; init; }

        [CommandOption("mode", Description = "GRLoadMode enum value")]
        public string Mode { get; init; } = "Create";

        public override Dictionary<string, object> Args() { var args = base.Args(); args["file"] = File; args["mode"] = Mode; return args; }
    }

    public abstract class PreLoginGalaxyCommandBase : ICommand
    {
        [CommandOption("node", 'n', Description = "GR node name. Blank = local node; . = local machine.")]
        public string NodeName { get; init; } = "";

        [CommandOption("confirm", Description = "Required for mutating commands")]
        public bool Confirm { get; init; }

        [CommandOption("confirm-target", Description = "Required exact target for destructive commands")]
        public string ConfirmTarget { get; init; } = "";

        protected IGRAccess CreateApp() => new GRAccessAppClass();
        protected string Node() => GRAccessDiagnostics.NormalizeNodeName(NodeName);
        public abstract ValueTask ExecuteAsync(IConsole console);
        protected void RequireConfirm(string target)
        {
            if (!Confirm) throw new CliFx.Exceptions.CommandException("This command requires --confirm.", 1);
            if (!string.Equals(ConfirmTarget, target, StringComparison.OrdinalIgnoreCase))
                throw new CliFx.Exceptions.CommandException($"This command requires --confirm-target {target}.", 1);
        }
    }

    [Command("galaxy create", Description = "Create a galaxy")]
    public sealed class GalaxyCreateCommand : PreLoginGalaxyCommandBase
    {
        [CommandOption("galaxy", 'g', Description = "Galaxy name", IsRequired = true)]
        public string GalaxyName { get; init; }

        [CommandOption("security", Description = "Enable security")]
        public bool Security { get; init; }

        [CommandOption("auth-mode", Description = "EAuthenticationMode enum value")]
        public string AuthMode { get; init; } = "aaNoAuthentication";

        [CommandOption("os-user", Description = "OS user name/description")]
        public string OsUser { get; init; } = "";

        public override ValueTask ExecuteAsync(IConsole console)
        {
            RequireConfirm(GalaxyName);
            var app = CreateApp();
            app.CreateGalaxy(GalaxyName, Node(), Security, (EAuthenticationMode)Enum.Parse(typeof(EAuthenticationMode), AuthMode), OsUser);
            console.Output.WriteLine(GRAccessDiagnostics.FormatCommandResult("CreateGalaxy", app.CommandResult));
            return default;
        }
    }

    [Command("galaxy create-from-template", Description = "Create a galaxy from a template")]
    public sealed class GalaxyCreateFromTemplateCommand : PreLoginGalaxyCommandBase
    {
        [CommandOption("galaxy", 'g', Description = "Galaxy name", IsRequired = true)]
        public string GalaxyName { get; init; }

        [CommandOption("template", Description = "Create galaxy template name", IsRequired = true)]
        public string Template { get; init; }

        public override ValueTask ExecuteAsync(IConsole console)
        {
            RequireConfirm(GalaxyName);
            var app = CreateApp();
            app.CreateGalaxyFromTemplate(Template, GalaxyName, Node());
            console.Output.WriteLine(GRAccessDiagnostics.FormatCommandResult("CreateGalaxyFromTemplate", app.CommandResult));
            return default;
        }
    }

    [Command("galaxy delete", Description = "Delete a galaxy")]
    public sealed class GalaxyDeleteCommand : PreLoginGalaxyCommandBase
    {
        [CommandOption("galaxy", 'g', Description = "Galaxy name", IsRequired = true)]
        public string GalaxyName { get; init; }

        public override ValueTask ExecuteAsync(IConsole console)
        {
            RequireConfirm(GalaxyName);
            var app = CreateApp();
            app.DeleteGalaxy(GalaxyName, Node());
            console.Output.WriteLine(GRAccessDiagnostics.FormatCommandResult("DeleteGalaxy", app.CommandResult));
            return default;
        }
    }

    [Command("object get", Description = "Get object details")]
    public sealed class ObjectGetCommand : ObjectCommandBase { public override string Command => "object"; public override string Subcommand => "get"; }

    [Command("object snapshot", Description = "Get a machine-oriented snapshot of an object, attributes, relationships, and script metadata")]
    public sealed class ObjectSnapshotCommand : ObjectCommandBase { public override string Command => "object"; public override string Subcommand => "snapshot"; }

    [Command("object lineage", Description = "Get object inheritance and containment lineage")]
    public sealed class ObjectLineageCommand : ObjectCommandBase { public override string Command => "object"; public override string Subcommand => "lineage"; }

    [Command("object children", Description = "Get contained or derived child objects")]
    public sealed class ObjectChildrenCommand : ObjectCommandBase { public override string Command => "object"; public override string Subcommand => "children"; }

    [Command("object query-name", Description = "Find objects by exact names")]
    public sealed class ObjectQueryNameCommand : RoutedCommandBase
    {
        public override string Command => "object";
        public override string Subcommand => "query-name";

        [CommandOption("name", Description = "Object tagname. May be repeated.", IsRequired = true)]
        public IReadOnlyList<string> Names { get; init; }

        [CommandOption("type", 't', Description = "Object type: all, template, instance")]
        public string Type { get; init; } = "all";

        public override Dictionary<string, object> Args() { var args = base.Args(); args["name"] = Names; args["type"] = Type; return args; }
    }

    [Command("object query-condition", Description = "Find objects by one GRAccess condition")]
    public sealed class ObjectQueryConditionCommand : RoutedCommandBase
    {
        public override string Command => "object";
        public override string Subcommand => "query-condition";

        [CommandOption("condition", Description = "EConditionType enum value")]
        public string Condition { get; init; } = "namedLike";

        [CommandOption("value", Description = "Condition value")]
        public string Value { get; init; } = "%";

        [CommandOption("type", 't', Description = "Object type: all, template, instance")]
        public string Type { get; init; } = "all";

        public override Dictionary<string, object> Args() { var args = base.Args(); args["condition"] = Condition; args["value"] = Value; args["type"] = Type; return args; }
    }

    [Command("object query-multi", Description = "Find objects matching any supplied pattern")]
    public sealed class ObjectQueryMultiCommand : RoutedCommandBase
    {
        public override string Command => "object";
        public override string Subcommand => "query-multi";

        [CommandOption("pattern", 'p', Description = "Name pattern. May be repeated.")]
        public IReadOnlyList<string> Patterns { get; init; } = Array.Empty<string>();

        [CommandOption("type", 't', Description = "Object type: all, template, instance")]
        public string Type { get; init; } = "all";

        public override Dictionary<string, object> Args() { var args = base.Args(); args["pattern"] = Patterns; args["type"] = Type; return args; }
    }

    [Command("object extended-attributes", Description = "Get extended attributes for an object")]
    public sealed class ObjectExtendedAttributesCommand : ObjectCommandBase
    {
        public override string Command => "object";
        public override string Subcommand => "extended-attributes";

        [CommandOption("attribute", Description = "Attribute name")]
        public string Attribute { get; init; } = "";

        [CommandOption("level", Description = "Hierarchy level")]
        public int Level { get; init; }

        public override Dictionary<string, object> Args() { var args = base.Args(); args["attribute"] = Attribute; args["level"] = Level; return args; }
    }

    [Command("object help-url", Description = "Get object help URL")]
    public sealed class ObjectHelpUrlCommand : ObjectCommandBase { public override string Command => "object"; public override string Subcommand => "help-url"; }

    [Command("object scripts list", Description = "List script-like metadata exposed on an object")]
    public sealed class ObjectScriptsListCommand : ObjectCommandBase { public override string Command => "object"; public override string Subcommand => "scripts-list"; }

    [Command("object scripts get", Description = "Get script metadata and body availability for an object script")]
    public class ObjectScriptsGetCommand : ObjectCommandBase
    {
        public override string Command => "object";
        public override string Subcommand => "scripts-get";

        [CommandOption("script", Description = "Script name", IsRequired = true)]
        public string Script { get; init; }

        public override Dictionary<string, object> Args() { var args = base.Args(); args["script"] = Script; return args; }
    }

    [Command("object scripts set", Description = "Set an object script text field via IAttribute.SetValue on ConfigurableAttributes (TN-537 pattern)")]
    public sealed class ObjectScriptsSetCommand : ObjectScriptsGetCommand
    {
        public override string Subcommand => "scripts-set";

        [CommandOption("file", Description = "Script source file", IsRequired = true)]
        public string File { get; init; }

        [CommandOption("field", Description = "Script-text field to write: ExecuteText (default), DeclarationsText, StartupText, ShutdownText, OnScanText, OffScanText, Expression. Pass to target a non-body field; omit to default to ExecuteText.")]
        public string Field { get; init; } = "";

        public override Dictionary<string, object> Args() { var args = base.Args(); args["file"] = File; args["field"] = Field; return args; }
    }

    [Command("object scripts delete", Description = "Delete a ScriptExtension primitive from an object")]
    public sealed class ObjectScriptsDeleteCommand : ObjectScriptsGetCommand
    {
        public override string Subcommand => "scripts-delete";
    }

    public abstract class ObjectScriptSettingsCommandBase : ObjectScriptsGetCommand
    {
        [CommandOption("trigger-period-ms", Description = "Periodic script trigger interval in milliseconds")]
        public string TriggerPeriodMs { get; init; } = "";

        [CommandOption("trigger-type", Description = "Script trigger type value")]
        public string TriggerType { get; init; } = "";

        [CommandOption("expression", Description = "Script expression value")]
        public string Expression { get; init; } = "";

        [CommandOption("lock-trigger-period", Description = "Lock TriggerPeriod in this object after setting it")]
        public bool LockTriggerPeriod { get; init; }

        [CommandOption("lock-trigger-type", Description = "Lock TriggerType in this object after setting it")]
        public bool LockTriggerType { get; init; }

        public override Dictionary<string, object> Args()
        {
            var args = base.Args();
            args["trigger-period-ms"] = TriggerPeriodMs;
            args["trigger-type"] = TriggerType;
            args["expression"] = Expression;
            args["lock-trigger-period"] = LockTriggerPeriod;
            args["lock-trigger-type"] = LockTriggerType;
            return args;
        }
    }

    [Command("object scripts create", Description = "Create a ScriptExtension primitive and optionally initialize its body/settings")]
    public sealed class ObjectScriptsCreateCommand : ObjectScriptSettingsCommandBase
    {
        public override string Subcommand => "scripts-create";

        [CommandOption("file", Description = "Optional script source file")]
        public string File { get; init; } = "";

        public override Dictionary<string, object> Args() { var args = base.Args(); args["file"] = File; return args; }
    }

    [Command("object scripts settings set", Description = "Set mutable ScriptExtension settings through ConfigurableAttributes")]
    public sealed class ObjectScriptsSettingsSetCommand : ObjectScriptSettingsCommandBase
    {
        public override string Subcommand => "scripts-settings-set";
    }

    [Command("object checkout", Description = "Check out an object")]
    public sealed class ObjectCheckoutCommand : ObjectCommandBase { public override string Command => "object"; public override string Subcommand => "checkout"; }

    [Command("object checkin", Description = "Check in an object")]
    public sealed class ObjectCheckinCommand : ObjectCommandBase
    {
        public override string Command => "object";
        public override string Subcommand => "checkin";

        [CommandOption("comment", Description = "Check-in comment")]
        public string Comment { get; init; } = "";

        public override Dictionary<string, object> Args() { var args = base.Args(); args["comment"] = Comment; return args; }
    }

    [Command("object undo-checkout", Description = "Undo object checkout")]
    public sealed class ObjectUndoCheckoutCommand : ObjectCommandBase { public override string Command => "object"; public override string Subcommand => "undo-checkout"; }

    [Command("object save", Description = "Save an object")]
    public sealed class ObjectSaveCommand : ObjectCommandBase { public override string Command => "object"; public override string Subcommand => "save"; }

    [Command("object unload", Description = "Unload an object from cache")]
    public sealed class ObjectUnloadCommand : ObjectCommandBase { public override string Command => "object"; public override string Subcommand => "unload"; }

    [Command("object set", Description = "Set an object property")]
    public sealed class ObjectSetCommand : ObjectCommandBase
    {
        public override string Command => "object";
        public override string Subcommand => "set";

        [CommandOption("property", Description = "tagname, contained-name, area, host, container, toolset, security-group", IsRequired = true)]
        public string Property { get; init; }

        [CommandOption("value", Description = "New value", IsRequired = true)]
        public string Value { get; init; }

        public override Dictionary<string, object> Args() { var args = base.Args(); args["property"] = Property; args["value"] = Value; return args; }
    }

    [Command("template derive", Description = "Create a derived template")]
    public sealed class TemplateDeriveCommand : ObjectCommandBase
    {
        public override string Command => "template";
        public override string Subcommand => "derive";
        [CommandOption("new-name", Description = "New template name", IsRequired = true)] public string NewName { get; init; }
        [CommandOption("create-contained", Description = "Create contained objects")] public bool CreateContained { get; init; }
        public override Dictionary<string, object> Args() { var args = base.Args(); args["new-name"] = NewName; args["create-contained"] = CreateContained; return args; }
    }

    [Command("template instantiate", Description = "Create an instance from a template")]
    public sealed class TemplateInstantiateCommand : ObjectCommandBase
    {
        public override string Command => "template";
        public override string Subcommand => "instantiate";
        [CommandOption("new-name", Description = "New instance name", IsRequired = true)] public string NewName { get; init; }
        [CommandOption("create-contained", Description = "Create contained objects")] public bool CreateContained { get; init; }
        public override Dictionary<string, object> Args() { var args = base.Args(); args["new-name"] = NewName; args["create-contained"] = CreateContained; return args; }
    }

    [Command("template delete", Description = "Delete a template")]
    public sealed class TemplateDeleteCommand : ObjectCommandBase
    {
        public override string Command => "template";
        public override string Subcommand => "delete";
        [CommandOption("force-option", Description = "EForceDeleteTemplateOption enum value")] public string ForceOption { get; init; } = "dontForceTemplateDelete";
        public override Dictionary<string, object> Args() { var args = base.Args(); args["force-option"] = ForceOption; return args; }
    }

    public abstract class InstanceLifecycleCommandBase : ObjectCommandBase
    {
        [CommandOption("force-option", Description = "Delete force option")]
        public string ForceOption { get; init; } = "undeployIfDeployed";

        public override Dictionary<string, object> Args() { var args = base.Args(); args["force-option"] = ForceOption; return args; }
    }

    [Command("instance delete", Description = "Delete an instance")]
    public sealed class InstanceDeleteCommand : InstanceLifecycleCommandBase { public override string Command => "instance"; public override string Subcommand => "delete"; }

    [Command("instance deploy", Description = "Deploy an instance")]
    public sealed class InstanceDeployCommand : ObjectCommandBase { public override string Command => "instance"; public override string Subcommand => "deploy"; }

    [Command("instance undeploy", Description = "Undeploy an instance")]
    public sealed class InstanceUndeployCommand : ObjectCommandBase { public override string Command => "instance"; public override string Subcommand => "undeploy"; }

    [Command("instance upload", Description = "Upload runtime changes for an instance")]
    public sealed class InstanceUploadCommand : ObjectCommandBase { public override string Command => "instance"; public override string Subcommand => "upload"; }

    [Command("instance assign-area", Description = "Assign an instance to an area")]
    public sealed class InstanceAssignAreaCommand : ObjectCommandBase
    {
        public override string Command => "instance";
        public override string Subcommand => "assign-area";
        [CommandOption("area", Description = "Area instance name", IsRequired = true)] public string Area { get; init; }
        public override Dictionary<string, object> Args() { var args = base.Args(); args["area"] = Area; return args; }
    }

    [Command("instance assign-engine", Description = "Assign an instance to an engine")]
    public sealed class InstanceAssignEngineCommand : ObjectCommandBase
    {
        public override string Command => "instance";
        public override string Subcommand => "assign-engine";
        [CommandOption("engine", Description = "Engine instance name", IsRequired = true)] public string Engine { get; init; }
        public override Dictionary<string, object> Args() { var args = base.Args(); args["engine"] = Engine; return args; }
    }

    [Command("instance assign-container", Description = "Assign an instance to a container")]
    public sealed class InstanceAssignContainerCommand : ObjectCommandBase
    {
        public override string Command => "instance";
        public override string Subcommand => "assign-container";
        [CommandOption("container", Description = "Container instance name", IsRequired = true)] public string Container { get; init; }
        public override Dictionary<string, object> Args() { var args = base.Args(); args["container"] = Container; return args; }
    }

    [Command("io assign", Description = "Assign an I/O-related instance attribute")]
    public sealed class IoAssignCommand : ConfirmedRoutedCommandBase
    {
        public override string Command => "io";
        public override string Subcommand => "assign";

        [CommandOption("name", Description = "Instance tagname", IsRequired = true)]
        public string ObjectName { get; init; }

        [CommandOption("attribute", Description = "Attribute name", IsRequired = true)]
        public string Attribute { get; init; }

        [CommandOption("value", Description = "Assigned value", IsRequired = true)]
        public string Value { get; init; }

        [CommandOption("data-type", Description = "string, bool, int, float, double")]
        public string DataType { get; init; } = "string";

        public override Dictionary<string, object> Args()
        {
            var args = base.Args();
            args["name"] = ObjectName;
            args["attribute"] = Attribute;
            args["value"] = Value;
            args["data-type"] = DataType;
            return args;
        }
    }

    public abstract class AreaEngineCommandBase : ConfirmedRoutedCommandBase
    {
        [CommandOption("template", Description = "Template to instantiate", IsRequired = true)]
        public string Template { get; init; }

        [CommandOption("name", Description = "New instance name", IsRequired = true)]
        public string Name { get; init; }

        [CommandOption("create-contained", Description = "Create contained objects")]
        public bool CreateContained { get; init; }

        public override Dictionary<string, object> Args()
        {
            var args = base.Args();
            args["template"] = Template;
            args["name"] = Name;
            args["create-contained"] = CreateContained;
            return args;
        }
    }

    [Command("area list", Description = "List area-like instances")]
    public sealed class AreaListCommand : RoutedCommandBase
    {
        public override string Command => "area";
        public override string Subcommand => "list";
        [CommandOption("pattern", 'p', Description = "Name pattern. Use % as wildcard.")] public string Pattern { get; init; } = "%Area%";
        public override Dictionary<string, object> Args() { var args = base.Args(); args["pattern"] = Pattern; return args; }
    }

    [Command("area create", Description = "Create an area instance from a template")]
    public sealed class AreaCreateCommand : AreaEngineCommandBase { public override string Command => "area"; public override string Subcommand => "create"; }

    [Command("engine list", Description = "List engine-like instances")]
    public sealed class EngineListCommand : RoutedCommandBase
    {
        public override string Command => "engine";
        public override string Subcommand => "list";
        [CommandOption("pattern", 'p', Description = "Name pattern. Use % as wildcard.")] public string Pattern { get; init; } = "%Engine%";
        public override Dictionary<string, object> Args() { var args = base.Args(); args["pattern"] = Pattern; return args; }
    }

    [Command("engine create", Description = "Create an engine instance from a template")]
    public sealed class EngineCreateCommand : AreaEngineCommandBase { public override string Command => "engine"; public override string Subcommand => "create"; }

    public abstract class AttributeCommandBase : ObjectCommandBase
    {
        [CommandOption("attribute", Description = "Attribute name", IsRequired = true)]
        public string Attribute { get; init; }
        public override Dictionary<string, object> Args() { var args = base.Args(); args["attribute"] = Attribute; return args; }
    }

    [Command("object attribute get", Description = "Get one attribute")]
    public sealed class ObjectAttributeGetCommand : AttributeCommandBase { public override string Command => "object"; public override string Subcommand => "attribute-get"; }

    [Command("object attribute set", Description = "Set one attribute value")]
    public sealed class ObjectAttributeSetCommand : AttributeCommandBase
    {
        public override string Command => "object";
        public override string Subcommand => "attribute-set";
        [CommandOption("value", Description = "New value", IsRequired = true)] public string Value { get; init; }
        [CommandOption("data-type", Description = "string, bool, int, float, double")] public string DataType { get; init; } = "string";
        public override Dictionary<string, object> Args() { var args = base.Args(); args["value"] = Value; args["data-type"] = DataType; return args; }
    }

    [Command("object attribute value get", Description = "Read back one attribute value with scalar type metadata")]
    public sealed class ObjectAttributeValueGetCommand : AttributeCommandBase { public override string Command => "object"; public override string Subcommand => "attribute-value-get"; }

    [Command("object attribute value set", Description = "Set one scalar attribute value")]
    public sealed class ObjectAttributeValueSetCommand : AttributeCommandBase
    {
        public override string Command => "object";
        public override string Subcommand => "attribute-value-set";
        [CommandOption("value", Description = "New value", IsRequired = true)] public string Value { get; init; }
        [CommandOption("data-type", Description = "string, bool, int, float, double")] public string DataType { get; init; } = "string";
        public override Dictionary<string, object> Args() { var args = base.Args(); args["value"] = Value; args["data-type"] = DataType; return args; }
    }

    [Command("object attribute lock", Description = "Set attribute locked state")]
    public sealed class ObjectAttributeLockCommand : AttributeCommandBase
    {
        public override string Command => "object"; public override string Subcommand => "attribute-lock";
        [CommandOption("locked", Description = "MxPropertyLockedEnum value", IsRequired = true)] public string Locked { get; init; }
        public override Dictionary<string, object> Args() { var args = base.Args(); args["locked"] = Locked; return args; }
    }

    [Command("object attribute security", Description = "Set attribute security classification")]
    public sealed class ObjectAttributeSecurityCommand : AttributeCommandBase
    {
        public override string Command => "object"; public override string Subcommand => "attribute-security";
        [CommandOption("security", Description = "MxSecurityClassification value", IsRequired = true)] public string Security { get; init; }
        public override Dictionary<string, object> Args() { var args = base.Args(); args["security"] = Security; return args; }
    }

    [Command("object attribute buffer", Description = "Set attribute buffer flag")]
    public sealed class ObjectAttributeBufferCommand : AttributeCommandBase
    {
        public override string Command => "object"; public override string Subcommand => "attribute-buffer";
        [CommandOption("has-buffer", Description = "Whether the attribute has a buffer")] public bool HasBuffer { get; init; }
        public override Dictionary<string, object> Args() { var args = base.Args(); args["has-buffer"] = HasBuffer; return args; }
    }

    public abstract class UdaCommandBase : ObjectCommandBase
    {
        [CommandOption("uda", Description = "UDA name", IsRequired = true)] public string Uda { get; init; }
        [CommandOption("data-type", Description = "MxDataType value")] public string DataType { get; init; } = "MxString";
        [CommandOption("category", Description = "MxAttributeCategory value")] public string Category { get; init; } = "MxCategoryWriteable_USC";
        [CommandOption("security", Description = "MxSecurityClassification value")] public string Security { get; init; } = "MxSecurityUndefined";
        [CommandOption("is-array", Description = "Create/update as array")] public bool IsArray { get; init; }
        [CommandOption("array-count", Description = "Array element count")] public int ArrayCount { get; init; }
        public override Dictionary<string, object> Args() { var args = base.Args(); args["uda"] = Uda; args["data-type"] = DataType; args["category"] = Category; args["security"] = Security; args["is-array"] = IsArray; args["array-count"] = ArrayCount; return args; }
    }

    [Command("object uda add", Description = "Add a UDA")]
    public sealed class ObjectUdaAddCommand : UdaCommandBase { public override string Command => "object"; public override string Subcommand => "uda-add"; }
    [Command("object uda delete", Description = "Delete a UDA")]
    public sealed class ObjectUdaDeleteCommand : UdaCommandBase { public override string Command => "object"; public override string Subcommand => "uda-delete"; }
    [Command("object uda rename", Description = "Rename a UDA")]
    public sealed class ObjectUdaRenameCommand : UdaCommandBase { public override string Command => "object"; public override string Subcommand => "uda-rename"; [CommandOption("new-name", Description = "New UDA name", IsRequired = true)] public string NewName { get; init; } public override Dictionary<string, object> Args() { var args = base.Args(); args["new-name"] = NewName; return args; } }
    [Command("object uda update", Description = "Update a UDA")]
    public sealed class ObjectUdaUpdateCommand : UdaCommandBase { public override string Command => "object"; public override string Subcommand => "uda-update"; }

    public abstract class ExtensionCommandBase : ObjectCommandBase
    {
        [CommandOption("extension-type", Description = "Extension type", IsRequired = true)] public string ExtensionType { get; init; }
        [CommandOption("primitive", Description = "Primitive name", IsRequired = true)] public string Primitive { get; init; }
        [CommandOption("object-extension", Description = "Whether this is an object extension")] public bool ObjectExtension { get; init; }
        public override Dictionary<string, object> Args() { var args = base.Args(); args["extension-type"] = ExtensionType; args["primitive"] = Primitive; args["object-extension"] = ObjectExtension; return args; }
    }

    [Command("object extension add", Description = "Add an extension primitive")]
    public sealed class ObjectExtensionAddCommand : ExtensionCommandBase { public override string Command => "object"; public override string Subcommand => "extension-add"; }
    [Command("object extension delete", Description = "Delete an extension primitive")]
    public sealed class ObjectExtensionDeleteCommand : ExtensionCommandBase { public override string Command => "object"; public override string Subcommand => "extension-delete"; }
    [Command("object extension rename", Description = "Rename an extension primitive")]
    public sealed class ObjectExtensionRenameCommand : ExtensionCommandBase { public override string Command => "object"; public override string Subcommand => "extension-rename"; [CommandOption("new-name", Description = "New primitive name", IsRequired = true)] public string NewName { get; init; } public override Dictionary<string, object> Args() { var args = base.Args(); args["new-name"] = NewName; return args; } }

    [Command("objects checkout", Description = "Check out multiple objects")]
    public sealed class ObjectsCheckoutCommand : BulkObjectsCommandBase { public override string Command => "objects"; public override string Subcommand => "checkout"; }
    [Command("objects checkin", Description = "Check in multiple objects")]
    public sealed class ObjectsCheckinCommand : BulkObjectsCommandBase { public override string Command => "objects"; public override string Subcommand => "checkin"; [CommandOption("comment", Description = "Check-in comment")] public string Comment { get; init; } = ""; public override Dictionary<string, object> Args() { var args = base.Args(); args["comment"] = Comment; return args; } }
    [Command("objects undo-checkout", Description = "Undo checkout for multiple objects")]
    public sealed class ObjectsUndoCheckoutCommand : BulkObjectsCommandBase { public override string Command => "objects"; public override string Subcommand => "undo-checkout"; }
    [Command("objects deploy", Description = "Deploy multiple instances")]
    public sealed class ObjectsDeployCommand : BulkObjectsCommandBase { public override string Command => "objects"; public override string Subcommand => "deploy"; }
    [Command("objects undeploy", Description = "Undeploy multiple instances")]
    public sealed class ObjectsUndeployCommand : BulkObjectsCommandBase { public override string Command => "objects"; public override string Subcommand => "undeploy"; }
    [Command("objects upload", Description = "Upload multiple instances")]
    public sealed class ObjectsUploadCommand : BulkObjectsCommandBase { public override string Command => "objects"; public override string Subcommand => "upload"; }
    [Command("objects delete", Description = "Delete multiple objects")]
    public sealed class ObjectsDeleteCommand : BulkObjectsCommandBase { public override string Command => "objects"; public override string Subcommand => "delete"; }
    [Command("objects export", Description = "Export multiple objects")]
    public sealed class ObjectsExportCommand : BulkObjectsCommandBase { public override string Command => "objects"; public override string Subcommand => "export"; [CommandOption("output", Description = "Output file path", IsRequired = true)] public string Output { get; init; } [CommandOption("export-type", Description = "EExportType value")] public string ExportType { get; init; } = "exportGalaxyDump"; public override Dictionary<string, object> Args() { var args = base.Args(); args["output"] = Output; args["export-type"] = ExportType; return args; } }
    [Command("objects export-protected", Description = "Export multiple objects as protected")]
    public sealed class ObjectsExportProtectedCommand : BulkObjectsCommandBase { public override string Command => "objects"; public override string Subcommand => "export-protected"; [CommandOption("output", Description = "Output file path", IsRequired = true)] public string Output { get; init; } public override Dictionary<string, object> Args() { var args = base.Args(); args["output"] = Output; return args; } }

    [Command("toolset list", Description = "List toolsets")]
    public sealed class ToolsetListCommand : RoutedCommandBase { public override string Command => "toolset"; public override string Subcommand => "list"; }
    [Command("toolset tree", Description = "Show toolset tree")]
    public sealed class ToolsetTreeCommand : RoutedCommandBase { public override string Command => "toolset"; public override string Subcommand => "tree"; }
    [Command("toolset add", Description = "Add a toolset")]
    public class ToolsetAddCommand : ConfirmedRoutedCommandBase { public override string Command => "toolset"; public override string Subcommand => "add"; [CommandOption("name", Description = "Toolset name", IsRequired = true)] public string Name { get; init; } public override Dictionary<string, object> Args() { var args = base.Args(); args["name"] = Name; return args; } }
    [Command("toolset delete", Description = "Delete a toolset")]
    public sealed class ToolsetDeleteCommand : ToolsetAddCommand { public override string Subcommand => "delete"; }
    [Command("toolset rename", Description = "Rename a toolset")]
    public sealed class ToolsetRenameCommand : ToolsetAddCommand { public override string Subcommand => "rename"; [CommandOption("new-name", Description = "New toolset name", IsRequired = true)] public string NewName { get; init; } public override Dictionary<string, object> Args() { var args = base.Args(); args["new-name"] = NewName; return args; } }
    [Command("toolset move", Description = "Move a toolset")]
    public sealed class ToolsetMoveCommand : ToolsetAddCommand { public override string Subcommand => "move"; [CommandOption("parent", Description = "Parent toolset name", IsRequired = true)] public string Parent { get; init; } public override Dictionary<string, object> Args() { var args = base.Args(); args["parent"] = Parent; return args; } }

    [Command("script-library list", Description = "List script libraries")]
    public sealed class ScriptLibraryListCommand : RoutedCommandBase { public override string Command => "script-library"; public override string Subcommand => "list"; }
    [Command("script-library add", Description = "Add/import a script library")]
    public class ScriptLibraryAddCommand : ConfirmedRoutedCommandBase { public override string Command => "script-library"; public override string Subcommand => "add"; [CommandOption("path", Description = "Script library path", IsRequired = true)] public string Path { get; init; } public override Dictionary<string, object> Args() { var args = base.Args(); args["path"] = Path; return args; } }
    [Command("script-library import", Description = "Import a script library")]
    public sealed class ScriptLibraryImportCommand : ScriptLibraryAddCommand { public override string Subcommand => "import"; }
    [Command("script-library export", Description = "Export a script library")]
    public sealed class ScriptLibraryExportCommand : ConfirmedRoutedCommandBase { public override string Command => "script-library"; public override string Subcommand => "export"; [CommandOption("name", Description = "Script library name", IsRequired = true)] public string Name { get; init; } [CommandOption("output", Description = "Output path", IsRequired = true)] public string Output { get; init; } public override Dictionary<string, object> Args() { var args = base.Args(); args["name"] = Name; args["output"] = Output; return args; } }

    [Command("security info", Description = "Show security settings")]
    public sealed class SecurityInfoCommand : RoutedCommandBase { public override string Command => "security"; public override string Subcommand => "info"; }
    [Command("security roles", Description = "List security roles")]
    public sealed class SecurityRolesCommand : RoutedCommandBase { public override string Command => "security"; public override string Subcommand => "roles"; }
    [Command("security users", Description = "List security users")]
    public sealed class SecurityUsersCommand : RoutedCommandBase { public override string Command => "security"; public override string Subcommand => "users"; }
    [Command("security groups", Description = "List security groups")]
    public sealed class SecurityGroupsCommand : RoutedCommandBase { public override string Command => "security"; public override string Subcommand => "groups"; }
    [Command("security permissions", Description = "List permissions for a role")]
    public sealed class SecurityPermissionsCommand : RoutedCommandBase { public override string Command => "security"; public override string Subcommand => "permissions"; [CommandOption("role", Description = "Role name", IsRequired = true)] public string Role { get; init; } public override Dictionary<string, object> Args() { var args = base.Args(); args["role"] = Role; return args; } }

    [Command("settings locale get", Description = "Get locale settings")]
    public sealed class SettingsLocaleGetCommand : RoutedCommandBase { public override string Command => "settings"; public override string Subcommand => "locale-get"; }
    [Command("settings time-master get", Description = "Get time master settings")]
    public sealed class SettingsTimeMasterGetCommand : RoutedCommandBase { public override string Command => "settings"; public override string Subcommand => "time-master-get"; }
}
