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 NotificationCommands
{
    /// <summary>
    /// Builds the <c>notification</c> command group with sub-commands for managing notification lists and SMTP configuration.
    /// </summary>
    /// <param name="urlOption">Global <c>--url</c> option for the management API endpoint.</param>
    /// <param name="formatOption">Global <c>--format</c> option for output format.</param>
    /// <param name="usernameOption">Global <c>--username</c> option for authentication.</param>
    /// <param name="passwordOption">Global <c>--password</c> option for authentication.</param>
    /// <returns>The configured <c>notification</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("notification") { Description = "Manage notification lists" };

        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(BuildSmtp(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 = "Notification list ID", Required = true };
        var cmd = new Command("get") { Description = "Get a notification list 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 GetNotificationListCommand(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 = "Notification list ID", Required = true };
        var nameOption = new Option<string>("--name") { Description = "List name", Required = true };
        var emailsOption = new Option<string>("--emails") { Description = "Comma-separated recipient emails", Required = true };

        var cmd = new Command("update") { Description = "Update a notification list" };
        cmd.Add(idOption);
        cmd.Add(nameOption);
        cmd.Add(emailsOption);
        cmd.SetAction(async (ParseResult result) =>
        {
            var id = result.GetValue(idOption);
            var name = result.GetValue(nameOption)!;
            var emailsRaw = result.GetValue(emailsOption)!;
            var emails = emailsRaw.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).ToList();
            return await CommandHelpers.ExecuteCommandAsync(
                result, urlOption, formatOption, usernameOption, passwordOption,
                new UpdateNotificationListCommand(id, name, emails));
        });
        return cmd;
    }

    private static Command BuildSmtp(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
    {
        var group = new Command("smtp") { Description = "Manage SMTP configuration" };

        var listCmd = new Command("list") { Description = "List SMTP configurations" };
        listCmd.SetAction(async (ParseResult result) =>
        {
            return await CommandHelpers.ExecuteCommandAsync(
                result, urlOption, formatOption, usernameOption, passwordOption, new ListSmtpConfigsCommand());
        });
        group.Add(listCmd);

        var updateCmd = new Command("update") { Description = "Update SMTP configuration" };
        updateCmd.Add(SmtpIdOption);
        updateCmd.Add(SmtpServerOption);
        updateCmd.Add(SmtpPortOption);
        updateCmd.Add(SmtpAuthModeOption);
        updateCmd.Add(SmtpFromOption);
        updateCmd.Add(SmtpTlsModeOption);
        updateCmd.Add(SmtpCredentialsOption);
        updateCmd.SetAction(async (ParseResult result) =>
        {
            return await CommandHelpers.ExecuteCommandAsync(
                result, urlOption, formatOption, usernameOption, passwordOption,
                BuildUpdateSmtpConfigCommand(result));
        });
        group.Add(updateCmd);

        return group;
    }

    // SMTP update options are static so the parsed values can be read back both
    // from the SetAction and from BuildUpdateSmtpConfigCommand (used by tests).
    private static readonly Option<int> SmtpIdOption =
        new("--id") { Description = "SMTP config ID", Required = true };
    private static readonly Option<string> SmtpServerOption =
        new("--server") { Description = "SMTP server", Required = true };
    private static readonly Option<int> SmtpPortOption =
        new("--port") { Description = "SMTP port", Required = true };
    private static readonly Option<string> SmtpAuthModeOption =
        new("--auth-mode") { Description = "Auth mode", Required = true };
    private static readonly Option<string> SmtpFromOption =
        new("--from-address") { Description = "From email address", Required = true };
    private static readonly Option<string?> SmtpTlsModeOption = CreateTlsModeOption();
    private static readonly Option<string?> SmtpCredentialsOption =
        new("--credentials")
        {
            Description = "SMTP credentials — 'username:password' for Basic, or client secret " +
                          "for OAuth2 (optional; preserves existing if omitted)",
        };

    private static Option<string?> CreateTlsModeOption()
    {
        var option = new Option<string?>("--tls-mode")
        {
            Description = "TLS mode: None, StartTLS, or SSL (optional; preserves existing if omitted)",
        };
        option.AcceptOnlyFromAmong("None", "StartTLS", "SSL");
        return option;
    }

    /// <summary>
    /// Builds the <see cref="UpdateSmtpConfigCommand"/> from a parsed <c>smtp update</c>
    /// invocation. The optional <c>--tls-mode</c> / <c>--credentials</c> flags map to
    /// null when omitted so the server-side handler preserves the existing values.
    /// </summary>
    /// <param name="result">The parsed command-line result from the <c>smtp update</c> invocation.</param>
    /// <returns>An <see cref="UpdateSmtpConfigCommand"/> populated from the parsed result.</returns>
    internal static UpdateSmtpConfigCommand BuildUpdateSmtpConfigCommand(ParseResult result)
    {
        var id = result.GetValue(SmtpIdOption);
        var server = result.GetValue(SmtpServerOption)!;
        var port = result.GetValue(SmtpPortOption);
        var authMode = result.GetValue(SmtpAuthModeOption)!;
        var from = result.GetValue(SmtpFromOption)!;
        var tlsMode = result.GetValue(SmtpTlsModeOption);
        var credentials = result.GetValue(SmtpCredentialsOption);
        return new UpdateSmtpConfigCommand(id, server, port, authMode, from, tlsMode, credentials);
    }

    private static Command BuildList(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
    {
        var cmd = new Command("list") { Description = "List all notification lists" };
        cmd.SetAction(async (ParseResult result) =>
        {
            return await CommandHelpers.ExecuteCommandAsync(
                result, urlOption, formatOption, usernameOption, passwordOption, new ListNotificationListsCommand());
        });
        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 = "Notification list name", Required = true };
        var emailsOption = new Option<string>("--emails") { Description = "Comma-separated recipient emails", Required = true };

        var cmd = new Command("create") { Description = "Create a notification list" };
        cmd.Add(nameOption);
        cmd.Add(emailsOption);
        cmd.SetAction(async (ParseResult result) =>
        {
            var name = result.GetValue(nameOption)!;
            var emailsRaw = result.GetValue(emailsOption)!;
            var emails = emailsRaw.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).ToList();
            return await CommandHelpers.ExecuteCommandAsync(
                result, urlOption, formatOption, usernameOption, passwordOption,
                new CreateNotificationListCommand(name, emails));
        });
        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 = "Notification list ID", Required = true };
        var cmd = new Command("delete") { Description = "Delete a notification list" };
        cmd.Add(idOption);
        cmd.SetAction(async (ParseResult result) =>
        {
            var id = result.GetValue(idOption);
            return await CommandHelpers.ExecuteCommandAsync(
                result, urlOption, formatOption, usernameOption, passwordOption, new DeleteNotificationListCommand(id));
        });
        return cmd;
    }
}
