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

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

public static class ExternalSystemCommands
{
    /// <summary>
    /// Builds the <c>external-system</c> CLI command group with subcommands for managing external systems.
    /// </summary>
    /// <param name="urlOption">Global option for the management URL.</param>
    /// <param name="formatOption">Global option for the output format.</param>
    /// <param name="usernameOption">Global option for the authentication username.</param>
    /// <param name="passwordOption">Global option for the authentication password.</param>
    /// <returns>The fully configured <c>external-system</c> <see cref="Command"/> with all subcommands registered.</returns>
    public static Command Build(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
    {
        var command = new Command("external-system") { Description = "Manage external systems" };

        command.Add(BuildList(urlOption, formatOption, usernameOption, passwordOption));
        command.Add(BuildGet(urlOption, formatOption, usernameOption, passwordOption));
        command.Add(BuildCreate(urlOption, formatOption, usernameOption, passwordOption));
        command.Add(BuildUpdate(urlOption, formatOption, usernameOption, passwordOption));
        command.Add(BuildDelete(urlOption, formatOption, usernameOption, passwordOption));
        command.Add(BuildMethodGroup(urlOption, formatOption, usernameOption, passwordOption));

        return command;
    }

    private static Command BuildGet(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
    {
        var idOption = new Option<int>("--id") { Description = "External system ID", Required = true };
        var cmd = new Command("get") { Description = "Get an external system by ID" };
        cmd.Add(idOption);
        cmd.SetAction(async (ParseResult result) =>
        {
            var id = result.GetValue(idOption);
            return await CommandHelpers.ExecuteCommandAsync(
                result, urlOption, formatOption, usernameOption, passwordOption, new GetExternalSystemCommand(id));
        });
        return cmd;
    }

    private static Command BuildUpdate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
    {
        var idOption = new Option<int>("--id") { Description = "External system ID", Required = true };
        var nameOption = new Option<string>("--name") { Description = "System name", Required = true };
        var endpointUrlOption = new Option<string>("--endpoint-url") { Description = "Endpoint URL", Required = true };
        var authTypeOption = new Option<string>("--auth-type") { Description = "Auth type", Required = true };
        var authConfigOption = new Option<string?>("--auth-config") { Description = "Auth configuration JSON" };
        var timeoutOption = new Option<int?>("--timeout-seconds") { Description = "Per-system HTTP timeout in seconds (0 = use gateway default); omit to preserve" };

        var cmd = new Command("update") { Description = "Update an external system" };
        cmd.Add(idOption);
        cmd.Add(nameOption);
        cmd.Add(endpointUrlOption);
        cmd.Add(authTypeOption);
        cmd.Add(authConfigOption);
        cmd.Add(timeoutOption);
        cmd.SetAction(async (ParseResult result) =>
        {
            var id = result.GetValue(idOption);
            var name = result.GetValue(nameOption)!;
            var endpointUrl = result.GetValue(endpointUrlOption)!;
            var authType = result.GetValue(authTypeOption)!;
            var authConfig = result.GetValue(authConfigOption);
            var timeoutSeconds = result.GetValue(timeoutOption);
            return await CommandHelpers.ExecuteCommandAsync(
                result, urlOption, formatOption, usernameOption, passwordOption,
                new UpdateExternalSystemCommand(id, name, endpointUrl, authType, authConfig, timeoutSeconds));
        });
        return cmd;
    }

    private static Command BuildList(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
    {
        var cmd = new Command("list") { Description = "List all external systems" };
        cmd.SetAction(async (ParseResult result) =>
        {
            return await CommandHelpers.ExecuteCommandAsync(
                result, urlOption, formatOption, usernameOption, passwordOption, new ListExternalSystemsCommand());
        });
        return cmd;
    }

    private static Command BuildCreate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
    {
        var nameOption = new Option<string>("--name") { Description = "System name", Required = true };
        var endpointUrlOption = new Option<string>("--endpoint-url") { Description = "Endpoint URL", Required = true };
        var authTypeOption = new Option<string>("--auth-type") { Description = "Auth type (ApiKey, BasicAuth)", Required = true };
        var authConfigOption = new Option<string?>("--auth-config") { Description = "Auth configuration JSON" };
        var timeoutOption = new Option<int?>("--timeout-seconds") { Description = "Per-system HTTP timeout in seconds (0 = use gateway default)" };

        var cmd = new Command("create") { Description = "Create an external system" };
        cmd.Add(nameOption);
        cmd.Add(endpointUrlOption);
        cmd.Add(authTypeOption);
        cmd.Add(authConfigOption);
        cmd.Add(timeoutOption);
        cmd.SetAction(async (ParseResult result) =>
        {
            var name = result.GetValue(nameOption)!;
            var endpointUrl = result.GetValue(endpointUrlOption)!;
            var authType = result.GetValue(authTypeOption)!;
            var authConfig = result.GetValue(authConfigOption);
            var timeoutSeconds = result.GetValue(timeoutOption);
            return await CommandHelpers.ExecuteCommandAsync(
                result, urlOption, formatOption, usernameOption, passwordOption,
                new CreateExternalSystemCommand(name, endpointUrl, authType, authConfig, timeoutSeconds));
        });
        return cmd;
    }

    private static Command BuildDelete(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
    {
        var idOption = new Option<int>("--id") { Description = "External system ID", Required = true };
        var cmd = new Command("delete") { Description = "Delete an external system" };
        cmd.Add(idOption);
        cmd.SetAction(async (ParseResult result) =>
        {
            var id = result.GetValue(idOption);
            return await CommandHelpers.ExecuteCommandAsync(
                result, urlOption, formatOption, usernameOption, passwordOption, new DeleteExternalSystemCommand(id));
        });
        return cmd;
    }

    // -- Method subcommands --

    private static Command BuildMethodGroup(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
    {
        var group = new Command("method") { Description = "Manage external system methods" };
        group.Add(BuildMethodList(urlOption, formatOption, usernameOption, passwordOption));
        group.Add(BuildMethodGet(urlOption, formatOption, usernameOption, passwordOption));
        group.Add(BuildMethodCreate(urlOption, formatOption, usernameOption, passwordOption));
        group.Add(BuildMethodUpdate(urlOption, formatOption, usernameOption, passwordOption));
        group.Add(BuildMethodDelete(urlOption, formatOption, usernameOption, passwordOption));
        return group;
    }

    private static Command BuildMethodList(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
    {
        var sysIdOption = new Option<int>("--external-system-id") { Description = "External system ID", Required = true };
        var cmd = new Command("list") { Description = "List methods for an external system" };
        cmd.Add(sysIdOption);
        cmd.SetAction(async (ParseResult result) =>
        {
            return await CommandHelpers.ExecuteCommandAsync(
                result, urlOption, formatOption, usernameOption, passwordOption,
                new ListExternalSystemMethodsCommand(result.GetValue(sysIdOption)));
        });
        return cmd;
    }

    private static Command BuildMethodGet(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
    {
        var idOption = new Option<int>("--id") { Description = "Method ID", Required = true };
        var cmd = new Command("get") { Description = "Get an external system method by ID" };
        cmd.Add(idOption);
        cmd.SetAction(async (ParseResult result) =>
        {
            return await CommandHelpers.ExecuteCommandAsync(
                result, urlOption, formatOption, usernameOption, passwordOption,
                new GetExternalSystemMethodCommand(result.GetValue(idOption)));
        });
        return cmd;
    }

    private static Command BuildMethodCreate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
    {
        var sysIdOption = new Option<int>("--external-system-id") { Description = "External system ID", Required = true };
        var nameOption = new Option<string>("--name") { Description = "Method name", Required = true };
        var httpMethodOption = new Option<string>("--http-method") { Description = "HTTP method (GET, POST, PUT, DELETE)", Required = true };
        var pathOption = new Option<string>("--path") { Description = "URL path (e.g. /api/Add)", Required = true };
        var paramsOption = new Option<string?>("--params") { Description = "Parameter definitions JSON" };
        var returnOption = new Option<string?>("--return") { Description = "Return definition JSON" };

        var cmd = new Command("create") { Description = "Create an external system method" };
        cmd.Add(sysIdOption);
        cmd.Add(nameOption);
        cmd.Add(httpMethodOption);
        cmd.Add(pathOption);
        cmd.Add(paramsOption);
        cmd.Add(returnOption);
        cmd.SetAction(async (ParseResult result) =>
        {
            return await CommandHelpers.ExecuteCommandAsync(
                result, urlOption, formatOption, usernameOption, passwordOption,
                new CreateExternalSystemMethodCommand(
                    result.GetValue(sysIdOption),
                    result.GetValue(nameOption)!,
                    result.GetValue(httpMethodOption)!,
                    result.GetValue(pathOption)!,
                    result.GetValue(paramsOption),
                    result.GetValue(returnOption)));
        });
        return cmd;
    }

    private static Command BuildMethodUpdate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
    {
        var idOption = new Option<int>("--id") { Description = "Method ID", Required = true };
        var nameOption = new Option<string?>("--name") { Description = "Method name" };
        var httpMethodOption = new Option<string?>("--http-method") { Description = "HTTP method" };
        var pathOption = new Option<string?>("--path") { Description = "URL path" };
        var paramsOption = new Option<string?>("--params") { Description = "Parameter definitions JSON" };
        var returnOption = new Option<string?>("--return") { Description = "Return definition JSON" };

        var cmd = new Command("update") { Description = "Update an external system method" };
        cmd.Add(idOption);
        cmd.Add(nameOption);
        cmd.Add(httpMethodOption);
        cmd.Add(pathOption);
        cmd.Add(paramsOption);
        cmd.Add(returnOption);
        cmd.SetAction(async (ParseResult result) =>
        {
            return await CommandHelpers.ExecuteCommandAsync(
                result, urlOption, formatOption, usernameOption, passwordOption,
                new UpdateExternalSystemMethodCommand(
                    result.GetValue(idOption),
                    result.GetValue(nameOption),
                    result.GetValue(httpMethodOption),
                    result.GetValue(pathOption),
                    result.GetValue(paramsOption),
                    result.GetValue(returnOption)));
        });
        return cmd;
    }

    private static Command BuildMethodDelete(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
    {
        var idOption = new Option<int>("--id") { Description = "Method ID", Required = true };
        var cmd = new Command("delete") { Description = "Delete an external system method" };
        cmd.Add(idOption);
        cmd.SetAction(async (ParseResult result) =>
        {
            return await CommandHelpers.ExecuteCommandAsync(
                result, urlOption, formatOption, usernameOption, passwordOption,
                new DeleteExternalSystemMethodCommand(result.GetValue(idOption)));
        });
        return cmd;
    }
}
