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 DataConnectionCommands
{
    /// <summary>
    /// Builds the <c>data-connection</c> command group and all 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>data-connection</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("data-connection") { Description = "Manage data connections" };

        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));

        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 = "Data connection ID", Required = true };
        var cmd = new Command("get") { Description = "Get a data connection 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 GetDataConnectionCommand(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 = "Data connection ID", Required = true };
        var nameOption = new Option<string>("--name") { Description = "Connection name", Required = true };
        var protocolOption = new Option<string>("--protocol") { Description = "Protocol", Required = true };
        var configOption = new Option<string?>("--primary-config", "--configuration") { Description = "Primary configuration JSON" };
        var backupConfigOption = new Option<string?>("--backup-config") { Description = "Backup configuration JSON" };
        var failoverRetryOption = new Option<int>("--failover-retry-count") { Description = "Number of retries before failover to backup", DefaultValueFactory = _ => 3 };

        var cmd = new Command("update") { Description = "Update a data connection" };
        cmd.Add(idOption);
        cmd.Add(nameOption);
        cmd.Add(protocolOption);
        cmd.Add(configOption);
        cmd.Add(backupConfigOption);
        cmd.Add(failoverRetryOption);
        cmd.SetAction(async (ParseResult result) =>
        {
            var id = result.GetValue(idOption);
            var name = result.GetValue(nameOption)!;
            var protocol = result.GetValue(protocolOption)!;
            var config = result.GetValue(configOption);
            var backupConfig = result.GetValue(backupConfigOption);
            var failoverRetryCount = result.GetValue(failoverRetryOption);
            return await CommandHelpers.ExecuteCommandAsync(
                result, urlOption, formatOption, usernameOption, passwordOption,
                new UpdateDataConnectionCommand(id, name, protocol, config, backupConfig, failoverRetryCount));
        });
        return cmd;
    }

    private static Command BuildList(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
    {
        var siteIdOption = new Option<int?>("--site-id") { Description = "Filter by site ID" };
        var cmd = new Command("list") { Description = "List data connections" };
        cmd.Add(siteIdOption);
        cmd.SetAction(async (ParseResult result) =>
        {
            var siteId = result.GetValue(siteIdOption);
            return await CommandHelpers.ExecuteCommandAsync(
                result, urlOption, formatOption, usernameOption, passwordOption, new ListDataConnectionsCommand(siteId));
        });
        return cmd;
    }

    private static Command BuildCreate(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
    {
        var siteIdOption = new Option<int>("--site-id") { Description = "Site ID", Required = true };
        var nameOption = new Option<string>("--name") { Description = "Connection name", Required = true };
        var protocolOption = new Option<string>("--protocol") { Description = "Protocol (e.g. OpcUa)", Required = true };
        var configOption = new Option<string?>("--primary-config", "--configuration") { Description = "Primary configuration JSON" };
        var backupConfigOption = new Option<string?>("--backup-config") { Description = "Backup configuration JSON" };
        var failoverRetryOption = new Option<int>("--failover-retry-count") { Description = "Number of retries before failover to backup", DefaultValueFactory = _ => 3 };

        var cmd = new Command("create") { Description = "Create a new data connection" };
        cmd.Add(siteIdOption);
        cmd.Add(nameOption);
        cmd.Add(protocolOption);
        cmd.Add(configOption);
        cmd.Add(backupConfigOption);
        cmd.Add(failoverRetryOption);
        cmd.SetAction(async (ParseResult result) =>
        {
            var siteId = result.GetValue(siteIdOption);
            var name = result.GetValue(nameOption)!;
            var protocol = result.GetValue(protocolOption)!;
            var config = result.GetValue(configOption);
            var backupConfig = result.GetValue(backupConfigOption);
            var failoverRetryCount = result.GetValue(failoverRetryOption);
            return await CommandHelpers.ExecuteCommandAsync(
                result, urlOption, formatOption, usernameOption, passwordOption,
                new CreateDataConnectionCommand(siteId, name, protocol, config, backupConfig, failoverRetryCount));
        });
        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 = "Data connection ID", Required = true };
        var cmd = new Command("delete") { Description = "Delete a data connection" };
        cmd.Add(idOption);
        cmd.SetAction(async (ParseResult result) =>
        {
            var id = result.GetValue(idOption);
            return await CommandHelpers.ExecuteCommandAsync(
                result, urlOption, formatOption, usernameOption, passwordOption, new DeleteDataConnectionCommand(id));
        });
        return cmd;
    }
}
