using System.CommandLine;
using System.CommandLine.Parsing;
using System.Text.Json;
using ScadaLink.Commons.Messages.Management;

namespace ScadaLink.CLI.Commands;

internal static class CommandHelpers
{
    internal static async Task<int> ExecuteCommandAsync(
        ParseResult result,
        Option<string> urlOption,
        Option<string> formatOption,
        Option<string> usernameOption,
        Option<string> passwordOption,
        object command)
    {
        var format = result.GetValue(formatOption) ?? "json";
        var config = CliConfig.Load();

        // Resolve management URL
        var url = result.GetValue(urlOption);
        if (string.IsNullOrWhiteSpace(url))
            url = config.ManagementUrl;

        if (string.IsNullOrWhiteSpace(url))
        {
            OutputFormatter.WriteError(
                "No management URL specified. Use --url, set SCADALINK_MANAGEMENT_URL, or add 'managementUrl' to ~/.scadalink/config.json.",
                "NO_URL");
            return 1;
        }

        // Validate credentials
        var username = result.GetValue(usernameOption);
        var password = result.GetValue(passwordOption);

        if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
        {
            OutputFormatter.WriteError(
                "Credentials required. Use --username and --password options.",
                "NO_CREDENTIALS");
            return 1;
        }

        // Derive command name from type
        var commandName = ManagementCommandRegistry.GetCommandName(command.GetType());

        // Send via HTTP
        using var client = new ManagementHttpClient(url, username, password);
        var response = await client.SendCommandAsync(commandName, command, TimeSpan.FromSeconds(30));

        return HandleResponse(response, format);
    }

    internal static int HandleResponse(ManagementResponse response, string format)
    {
        if (response.JsonData != null)
        {
            if (string.Equals(format, "table", StringComparison.OrdinalIgnoreCase))
            {
                WriteAsTable(response.JsonData);
            }
            else
            {
                Console.WriteLine(response.JsonData);
            }
            return 0;
        }

        var errorCode = response.ErrorCode ?? "ERROR";
        var error = response.Error ?? "Unknown error";

        OutputFormatter.WriteError(error, errorCode);
        return response.StatusCode == 403 ? 2 : 1;
    }

    private static void WriteAsTable(string json)
    {
        using var doc = JsonDocument.Parse(json);
        var root = doc.RootElement;

        if (root.ValueKind == JsonValueKind.Array)
        {
            var items = root.EnumerateArray().ToList();
            if (items.Count == 0)
            {
                Console.WriteLine("(no results)");
                return;
            }

            var headers = items[0].ValueKind == JsonValueKind.Object
                ? items[0].EnumerateObject().Select(p => p.Name).ToArray()
                : new[] { "Value" };

            var rows = items.Select(item =>
            {
                if (item.ValueKind == JsonValueKind.Object)
                {
                    return headers.Select(h =>
                        item.TryGetProperty(h, out var val)
                            ? val.ValueKind == JsonValueKind.Null ? "" : val.ToString()
                            : "").ToArray();
                }
                return new[] { item.ToString() };
            });

            OutputFormatter.WriteTable(rows, headers);
        }
        else if (root.ValueKind == JsonValueKind.Object)
        {
            var headers = new[] { "Property", "Value" };
            var rows = root.EnumerateObject().Select(p =>
                new[] { p.Name, p.Value.ValueKind == JsonValueKind.Null ? "" : p.Value.ToString() });
            OutputFormatter.WriteTable(rows, headers);
        }
        else
        {
            Console.WriteLine(root.ToString());
        }
    }
}
