using System;
using System.Buffers;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Security.Cryptography;
using System.Text.Json;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Spectre.Console;
using StellaOps.Auth.Client;
using StellaOps.Cli.Configuration;
using StellaOps.Cli.Prompts;
using StellaOps.Cli.Services;
using StellaOps.Cli.Services.Models;
using StellaOps.Cli.Telemetry;
using StellaOps.Cryptography;

namespace StellaOps.Cli.Commands;

internal static class CommandHandlers
{
    public static async Task HandleScannerDownloadAsync(
        IServiceProvider services,
        string channel,
        string? output,
        bool overwrite,
        bool install,
        bool verbose,
        CancellationToken cancellationToken)
    {
        await using var scope = services.CreateAsyncScope();
        var client = scope.ServiceProvider.GetRequiredService<IBackendOperationsClient>();
        var logger = scope.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger("scanner-download");
        var verbosity = scope.ServiceProvider.GetRequiredService<VerbosityState>();
        var previousLevel = verbosity.MinimumLevel;
        verbosity.MinimumLevel = verbose ? LogLevel.Debug : LogLevel.Information;
        using var activity = CliActivitySource.Instance.StartActivity("cli.scanner.download", ActivityKind.Client);
        activity?.SetTag("stellaops.cli.command", "scanner download");
        activity?.SetTag("stellaops.cli.channel", channel);
        using var duration = CliMetrics.MeasureCommandDuration("scanner download");

        try
        {
            var result = await client.DownloadScannerAsync(channel, output ?? string.Empty, overwrite, verbose, cancellationToken).ConfigureAwait(false);

            if (result.FromCache)
            {
                logger.LogInformation("Using cached scanner at {Path}.", result.Path);
            }
            else
            {
                logger.LogInformation("Scanner downloaded to {Path} ({Size} bytes).", result.Path, result.SizeBytes);
            }

            CliMetrics.RecordScannerDownload(channel, result.FromCache);

            if (install)
            {
                var installer = scope.ServiceProvider.GetRequiredService<IScannerInstaller>();
                await installer.InstallAsync(result.Path, verbose, cancellationToken).ConfigureAwait(false);
                CliMetrics.RecordScannerInstall(channel);
            }

            Environment.ExitCode = 0;
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Failed to download scanner bundle.");
            Environment.ExitCode = 1;
        }
        finally
        {
            verbosity.MinimumLevel = previousLevel;
        }
    }

    public static async Task HandleScannerRunAsync(
        IServiceProvider services,
        string runner,
        string entry,
        string targetDirectory,
        IReadOnlyList<string> arguments,
        bool verbose,
        CancellationToken cancellationToken)
    {
        await using var scope = services.CreateAsyncScope();
        var executor = scope.ServiceProvider.GetRequiredService<IScannerExecutor>();
        var logger = scope.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger("scanner-run");
        var verbosity = scope.ServiceProvider.GetRequiredService<VerbosityState>();
        var previousLevel = verbosity.MinimumLevel;
        verbosity.MinimumLevel = verbose ? LogLevel.Debug : LogLevel.Information;
        using var activity = CliActivitySource.Instance.StartActivity("cli.scan.run", ActivityKind.Internal);
        activity?.SetTag("stellaops.cli.command", "scan run");
        activity?.SetTag("stellaops.cli.runner", runner);
        activity?.SetTag("stellaops.cli.entry", entry);
        activity?.SetTag("stellaops.cli.target", targetDirectory);
        using var duration = CliMetrics.MeasureCommandDuration("scan run");

        try
        {
            var options = scope.ServiceProvider.GetRequiredService<StellaOpsCliOptions>();
            var resultsDirectory = options.ResultsDirectory;

            var executionResult = await executor.RunAsync(
                runner,
                entry,
                targetDirectory,
                resultsDirectory,
                arguments,
                verbose,
                cancellationToken).ConfigureAwait(false);

            Environment.ExitCode = executionResult.ExitCode;
            CliMetrics.RecordScanRun(runner, executionResult.ExitCode);

            if (executionResult.ExitCode == 0)
            {
                var backend = scope.ServiceProvider.GetRequiredService<IBackendOperationsClient>();
                logger.LogInformation("Uploading scan artefact {Path}...", executionResult.ResultsPath);
                await backend.UploadScanResultsAsync(executionResult.ResultsPath, cancellationToken).ConfigureAwait(false);
                logger.LogInformation("Scan artefact uploaded.");
                activity?.SetTag("stellaops.cli.results", executionResult.ResultsPath);
            }
            else
            {
                logger.LogWarning("Skipping automatic upload because scan exited with code {Code}.", executionResult.ExitCode);
            }

            logger.LogInformation("Run metadata written to {Path}.", executionResult.RunMetadataPath);
            activity?.SetTag("stellaops.cli.run_metadata", executionResult.RunMetadataPath);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Scanner execution failed.");
            Environment.ExitCode = 1;
        }
        finally
        {
            verbosity.MinimumLevel = previousLevel;
        }
    }

    public static async Task HandleScanUploadAsync(
        IServiceProvider services,
        string file,
        bool verbose,
        CancellationToken cancellationToken)
    {
        await using var scope = services.CreateAsyncScope();
        var client = scope.ServiceProvider.GetRequiredService<IBackendOperationsClient>();
        var logger = scope.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger("scanner-upload");
        var verbosity = scope.ServiceProvider.GetRequiredService<VerbosityState>();
        var previousLevel = verbosity.MinimumLevel;
        verbosity.MinimumLevel = verbose ? LogLevel.Debug : LogLevel.Information;
        using var activity = CliActivitySource.Instance.StartActivity("cli.scan.upload", ActivityKind.Client);
        activity?.SetTag("stellaops.cli.command", "scan upload");
        activity?.SetTag("stellaops.cli.file", file);
        using var duration = CliMetrics.MeasureCommandDuration("scan upload");

        try
        {
            var path = Path.GetFullPath(file);
            await client.UploadScanResultsAsync(path, cancellationToken).ConfigureAwait(false);
            logger.LogInformation("Scan results uploaded successfully.");
            Environment.ExitCode = 0;
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Failed to upload scan results.");
            Environment.ExitCode = 1;
        }
        finally
        {
            verbosity.MinimumLevel = previousLevel;
        }
    }

    public static async Task HandleConnectorJobAsync(
        IServiceProvider services,
        string source,
        string stage,
        string? mode,
        bool verbose,
        CancellationToken cancellationToken)
    {
        await using var scope = services.CreateAsyncScope();
        var client = scope.ServiceProvider.GetRequiredService<IBackendOperationsClient>();
        var logger = scope.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger("db-connector");
        var verbosity = scope.ServiceProvider.GetRequiredService<VerbosityState>();
        var previousLevel = verbosity.MinimumLevel;
        verbosity.MinimumLevel = verbose ? LogLevel.Debug : LogLevel.Information;
        using var activity = CliActivitySource.Instance.StartActivity("cli.db.fetch", ActivityKind.Client);
        activity?.SetTag("stellaops.cli.command", "db fetch");
        activity?.SetTag("stellaops.cli.source", source);
        activity?.SetTag("stellaops.cli.stage", stage);
        if (!string.IsNullOrWhiteSpace(mode))
        {
            activity?.SetTag("stellaops.cli.mode", mode);
        }
        using var duration = CliMetrics.MeasureCommandDuration("db fetch");

        try
        {
            var jobKind = $"source:{source}:{stage}";
            var parameters = new Dictionary<string, object?>(StringComparer.Ordinal);
            if (!string.IsNullOrWhiteSpace(mode))
            {
                parameters["mode"] = mode;
            }

            await TriggerJobAsync(client, logger, jobKind, parameters, cancellationToken).ConfigureAwait(false);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Connector job failed.");
            Environment.ExitCode = 1;
        }
        finally
        {
            verbosity.MinimumLevel = previousLevel;
        }
    }

    public static async Task HandleMergeJobAsync(
        IServiceProvider services,
        bool verbose,
        CancellationToken cancellationToken)
    {
        await using var scope = services.CreateAsyncScope();
        var client = scope.ServiceProvider.GetRequiredService<IBackendOperationsClient>();
        var logger = scope.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger("db-merge");
        var verbosity = scope.ServiceProvider.GetRequiredService<VerbosityState>();
        var previousLevel = verbosity.MinimumLevel;
        verbosity.MinimumLevel = verbose ? LogLevel.Debug : LogLevel.Information;
        using var activity = CliActivitySource.Instance.StartActivity("cli.db.merge", ActivityKind.Client);
        activity?.SetTag("stellaops.cli.command", "db merge");
        using var duration = CliMetrics.MeasureCommandDuration("db merge");

        try
        {
            await TriggerJobAsync(client, logger, "merge:reconcile", new Dictionary<string, object?>(StringComparer.Ordinal), cancellationToken).ConfigureAwait(false);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Merge job failed.");
            Environment.ExitCode = 1;
        }
        finally
        {
            verbosity.MinimumLevel = previousLevel;
        }
    }

    public static async Task HandleExportJobAsync(
        IServiceProvider services,
        string format,
        bool delta,
        bool? publishFull,
        bool? publishDelta,
        bool? includeFull,
        bool? includeDelta,
        bool verbose,
        CancellationToken cancellationToken)
    {
        await using var scope = services.CreateAsyncScope();
        var client = scope.ServiceProvider.GetRequiredService<IBackendOperationsClient>();
        var logger = scope.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger("db-export");
        var verbosity = scope.ServiceProvider.GetRequiredService<VerbosityState>();
        var previousLevel = verbosity.MinimumLevel;
        verbosity.MinimumLevel = verbose ? LogLevel.Debug : LogLevel.Information;
        using var activity = CliActivitySource.Instance.StartActivity("cli.db.export", ActivityKind.Client);
        activity?.SetTag("stellaops.cli.command", "db export");
        activity?.SetTag("stellaops.cli.format", format);
        activity?.SetTag("stellaops.cli.delta", delta);
        using var duration = CliMetrics.MeasureCommandDuration("db export");
        activity?.SetTag("stellaops.cli.publish_full", publishFull);
        activity?.SetTag("stellaops.cli.publish_delta", publishDelta);
        activity?.SetTag("stellaops.cli.include_full", includeFull);
        activity?.SetTag("stellaops.cli.include_delta", includeDelta);

        try
        {
            var jobKind = format switch
            {
                "trivy-db" or "trivy" => "export:trivy-db",
                _ => "export:json"
            };

            var isTrivy = jobKind == "export:trivy-db";
            if (isTrivy
                && !publishFull.HasValue
                && !publishDelta.HasValue
                && !includeFull.HasValue
                && !includeDelta.HasValue
                && AnsiConsole.Profile.Capabilities.Interactive)
            {
                var overrides = TrivyDbExportPrompt.PromptOverrides();
                publishFull = overrides.publishFull;
                publishDelta = overrides.publishDelta;
                includeFull = overrides.includeFull;
                includeDelta = overrides.includeDelta;
            }

            var parameters = new Dictionary<string, object?>(StringComparer.Ordinal)
            {
                ["delta"] = delta
            };
            if (publishFull.HasValue)
            {
                parameters["publishFull"] = publishFull.Value;
            }
            if (publishDelta.HasValue)
            {
                parameters["publishDelta"] = publishDelta.Value;
            }
            if (includeFull.HasValue)
            {
                parameters["includeFull"] = includeFull.Value;
            }
            if (includeDelta.HasValue)
            {
                parameters["includeDelta"] = includeDelta.Value;
            }

            await TriggerJobAsync(client, logger, jobKind, parameters, cancellationToken).ConfigureAwait(false);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Export job failed.");
            Environment.ExitCode = 1;
        }
        finally
        {
            verbosity.MinimumLevel = previousLevel;
        }
    }

    public static async Task HandleAuthLoginAsync(
        IServiceProvider services,
        StellaOpsCliOptions options,
        bool verbose,
        bool force,
        CancellationToken cancellationToken)
    {
        await using var scope = services.CreateAsyncScope();
        var logger = scope.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger("auth-login");
        Environment.ExitCode = 0;

        if (string.IsNullOrWhiteSpace(options.Authority?.Url))
        {
            logger.LogError("Authority URL is not configured. Set STELLAOPS_AUTHORITY_URL or update your configuration.");
            Environment.ExitCode = 1;
            return;
        }

        var tokenClient = scope.ServiceProvider.GetService<IStellaOpsTokenClient>();
        if (tokenClient is null)
        {
            logger.LogError("Authority client is not available. Ensure AddStellaOpsAuthClient is registered in Program.cs.");
            Environment.ExitCode = 1;
            return;
        }

        var cacheKey = AuthorityTokenUtilities.BuildCacheKey(options);
        if (string.IsNullOrWhiteSpace(cacheKey))
        {
            logger.LogError("Authority configuration is incomplete; unable to determine cache key.");
            Environment.ExitCode = 1;
            return;
        }

        try
        {
            if (force)
            {
                await tokenClient.ClearCachedTokenAsync(cacheKey, cancellationToken).ConfigureAwait(false);
            }

            var scopeName = AuthorityTokenUtilities.ResolveScope(options);
            StellaOpsTokenResult token;

            if (!string.IsNullOrWhiteSpace(options.Authority.Username))
            {
                if (string.IsNullOrWhiteSpace(options.Authority.Password))
                {
                    logger.LogError("Authority password must be provided when username is configured.");
                    Environment.ExitCode = 1;
                    return;
                }

                token = await tokenClient.RequestPasswordTokenAsync(
                    options.Authority.Username,
                    options.Authority.Password!,
                    scopeName,
                    cancellationToken).ConfigureAwait(false);
            }
            else
            {
                token = await tokenClient.RequestClientCredentialsTokenAsync(scopeName, cancellationToken).ConfigureAwait(false);
            }

            await tokenClient.CacheTokenAsync(cacheKey, token.ToCacheEntry(), cancellationToken).ConfigureAwait(false);

            if (verbose)
            {
                logger.LogInformation("Authenticated with {Authority} (scopes: {Scopes}).", options.Authority.Url, string.Join(", ", token.Scopes));
            }

            logger.LogInformation("Login successful. Access token expires at {Expires}.", token.ExpiresAtUtc.ToString("u"));
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Authentication failed: {Message}", ex.Message);
            Environment.ExitCode = 1;
        }
    }

    public static async Task HandleAuthLogoutAsync(
        IServiceProvider services,
        StellaOpsCliOptions options,
        bool verbose,
        CancellationToken cancellationToken)
    {
        await using var scope = services.CreateAsyncScope();
        var logger = scope.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger("auth-logout");
        Environment.ExitCode = 0;

        var tokenClient = scope.ServiceProvider.GetService<IStellaOpsTokenClient>();
        if (tokenClient is null)
        {
            logger.LogInformation("No authority client registered; nothing to remove.");
            return;
        }

        var cacheKey = AuthorityTokenUtilities.BuildCacheKey(options);
        if (string.IsNullOrWhiteSpace(cacheKey))
        {
            logger.LogInformation("Authority configuration missing; no cached tokens to remove.");
            return;
        }

        await tokenClient.ClearCachedTokenAsync(cacheKey, cancellationToken).ConfigureAwait(false);
        if (verbose)
        {
            logger.LogInformation("Cleared cached token for {Authority}.", options.Authority?.Url ?? "authority");
        }
    }

    public static async Task HandleAuthStatusAsync(
        IServiceProvider services,
        StellaOpsCliOptions options,
        bool verbose,
        CancellationToken cancellationToken)
    {
        await using var scope = services.CreateAsyncScope();
        var logger = scope.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger("auth-status");
        Environment.ExitCode = 0;

        if (string.IsNullOrWhiteSpace(options.Authority?.Url))
        {
            logger.LogInformation("Authority URL not configured. Set STELLAOPS_AUTHORITY_URL and run 'auth login'.");
            Environment.ExitCode = 1;
            return;
        }

        var tokenClient = scope.ServiceProvider.GetService<IStellaOpsTokenClient>();
        if (tokenClient is null)
        {
            logger.LogInformation("Authority client not registered; no cached tokens available.");
            Environment.ExitCode = 1;
            return;
        }

        var cacheKey = AuthorityTokenUtilities.BuildCacheKey(options);
        if (string.IsNullOrWhiteSpace(cacheKey))
        {
            logger.LogInformation("Authority configuration incomplete; no cached tokens available.");
            Environment.ExitCode = 1;
            return;
        }

        var entry = await tokenClient.GetCachedTokenAsync(cacheKey, cancellationToken).ConfigureAwait(false);
        if (entry is null)
        {
            logger.LogInformation("No cached token for {Authority}. Run 'auth login' to authenticate.", options.Authority.Url);
            Environment.ExitCode = 1;
            return;
        }

        logger.LogInformation("Cached token for {Authority} expires at {Expires}.", options.Authority.Url, entry.ExpiresAtUtc.ToString("u"));
        if (verbose)
        {
            logger.LogInformation("Scopes: {Scopes}", string.Join(", ", entry.Scopes));
        }
    }

    public static async Task HandleAuthWhoAmIAsync(
        IServiceProvider services,
        StellaOpsCliOptions options,
        bool verbose,
        CancellationToken cancellationToken)
    {
        await using var scope = services.CreateAsyncScope();
        var logger = scope.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger("auth-whoami");
        Environment.ExitCode = 0;

        if (string.IsNullOrWhiteSpace(options.Authority?.Url))
        {
            logger.LogInformation("Authority URL not configured. Set STELLAOPS_AUTHORITY_URL and run 'auth login'.");
            Environment.ExitCode = 1;
            return;
        }

        var tokenClient = scope.ServiceProvider.GetService<IStellaOpsTokenClient>();
        if (tokenClient is null)
        {
            logger.LogInformation("Authority client not registered; no cached tokens available.");
            Environment.ExitCode = 1;
            return;
        }

        var cacheKey = AuthorityTokenUtilities.BuildCacheKey(options);
        if (string.IsNullOrWhiteSpace(cacheKey))
        {
            logger.LogInformation("Authority configuration incomplete; no cached tokens available.");
            Environment.ExitCode = 1;
            return;
        }

        var entry = await tokenClient.GetCachedTokenAsync(cacheKey, cancellationToken).ConfigureAwait(false);
        if (entry is null)
        {
            logger.LogInformation("No cached token for {Authority}. Run 'auth login' to authenticate.", options.Authority.Url);
            Environment.ExitCode = 1;
            return;
        }

        var grantType = string.IsNullOrWhiteSpace(options.Authority.Username) ? "client_credentials" : "password";
        var now = DateTimeOffset.UtcNow;
        var remaining = entry.ExpiresAtUtc - now;
        if (remaining < TimeSpan.Zero)
        {
            remaining = TimeSpan.Zero;
        }

        logger.LogInformation("Authority: {Authority}", options.Authority.Url);
        logger.LogInformation("Grant type: {GrantType}", grantType);
        logger.LogInformation("Token type: {TokenType}", entry.TokenType);
        logger.LogInformation("Expires: {Expires} ({Remaining})", entry.ExpiresAtUtc.ToString("u"), FormatDuration(remaining));

        if (entry.Scopes.Count > 0)
        {
            logger.LogInformation("Scopes: {Scopes}", string.Join(", ", entry.Scopes));
        }

        if (TryExtractJwtClaims(entry.AccessToken, out var claims, out var issuedAt, out var notBefore))
        {
            if (claims.TryGetValue("sub", out var subject) && !string.IsNullOrWhiteSpace(subject))
            {
                logger.LogInformation("Subject: {Subject}", subject);
            }

            if (claims.TryGetValue("client_id", out var clientId) && !string.IsNullOrWhiteSpace(clientId))
            {
                logger.LogInformation("Client ID (token): {ClientId}", clientId);
            }

            if (claims.TryGetValue("aud", out var audience) && !string.IsNullOrWhiteSpace(audience))
            {
                logger.LogInformation("Audience: {Audience}", audience);
            }

            if (claims.TryGetValue("iss", out var issuer) && !string.IsNullOrWhiteSpace(issuer))
            {
                logger.LogInformation("Issuer: {Issuer}", issuer);
            }

            if (issuedAt is not null)
            {
                logger.LogInformation("Issued at: {IssuedAt}", issuedAt.Value.ToString("u"));
            }

            if (notBefore is not null)
            {
                logger.LogInformation("Not before: {NotBefore}", notBefore.Value.ToString("u"));
            }

            var extraClaims = CollectAdditionalClaims(claims);
            if (extraClaims.Count > 0 && verbose)
            {
                logger.LogInformation("Additional claims: {Claims}", string.Join(", ", extraClaims));
            }
        }
        else
        {
            logger.LogInformation("Access token appears opaque; claims are unavailable.");
        }
    }

    public static async Task HandleAuthRevokeExportAsync(
        IServiceProvider services,
        StellaOpsCliOptions options,
        string? outputDirectory,
        bool verbose,
        CancellationToken cancellationToken)
    {
        await using var scope = services.CreateAsyncScope();
        var logger = scope.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger("auth-revoke-export");
        Environment.ExitCode = 0;

        try
        {
            var client = scope.ServiceProvider.GetRequiredService<IAuthorityRevocationClient>();
            var result = await client.ExportAsync(verbose, cancellationToken).ConfigureAwait(false);

            var directory = string.IsNullOrWhiteSpace(outputDirectory)
                ? Directory.GetCurrentDirectory()
                : Path.GetFullPath(outputDirectory);

            Directory.CreateDirectory(directory);

            var bundlePath = Path.Combine(directory, "revocation-bundle.json");
            var signaturePath = Path.Combine(directory, "revocation-bundle.json.jws");
            var digestPath = Path.Combine(directory, "revocation-bundle.json.sha256");

            await File.WriteAllBytesAsync(bundlePath, result.BundleBytes, cancellationToken).ConfigureAwait(false);
            await File.WriteAllTextAsync(signaturePath, result.Signature, cancellationToken).ConfigureAwait(false);
            await File.WriteAllTextAsync(digestPath, $"sha256:{result.Digest}", cancellationToken).ConfigureAwait(false);

            var computedDigest = Convert.ToHexString(SHA256.HashData(result.BundleBytes)).ToLowerInvariant();
            if (!string.Equals(computedDigest, result.Digest, StringComparison.OrdinalIgnoreCase))
            {
                logger.LogError("Digest mismatch. Expected {Expected} but computed {Actual}.", result.Digest, computedDigest);
                Environment.ExitCode = 1;
                return;
            }

            logger.LogInformation(
                "Revocation bundle exported to {Directory} (sequence {Sequence}, issued {Issued:u}, signing key {KeyId}, provider {Provider}).",
                directory,
                result.Sequence,
                result.IssuedAt,
                string.IsNullOrWhiteSpace(result.SigningKeyId) ? "<unknown>" : result.SigningKeyId,
                string.IsNullOrWhiteSpace(result.SigningProvider) ? "default" : result.SigningProvider);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Failed to export revocation bundle.");
            Environment.ExitCode = 1;
        }
    }

    public static async Task HandleAuthRevokeVerifyAsync(
        string bundlePath,
        string signaturePath,
        string keyPath,
        bool verbose,
        CancellationToken cancellationToken)
    {
        var loggerFactory = LoggerFactory.Create(builder => builder.AddSimpleConsole(options =>
        {
            options.SingleLine = true;
            options.TimestampFormat = "HH:mm:ss ";
        }));
        var logger = loggerFactory.CreateLogger("auth-revoke-verify");
        Environment.ExitCode = 0;

        try
        {
            if (string.IsNullOrWhiteSpace(bundlePath) || string.IsNullOrWhiteSpace(signaturePath) || string.IsNullOrWhiteSpace(keyPath))
            {
                logger.LogError("Arguments --bundle, --signature, and --key are required.");
                Environment.ExitCode = 1;
                return;
            }

            var bundleBytes = await File.ReadAllBytesAsync(bundlePath, cancellationToken).ConfigureAwait(false);
            var signatureContent = (await File.ReadAllTextAsync(signaturePath, cancellationToken).ConfigureAwait(false)).Trim();
            var keyPem = await File.ReadAllTextAsync(keyPath, cancellationToken).ConfigureAwait(false);

            var digest = Convert.ToHexString(SHA256.HashData(bundleBytes)).ToLowerInvariant();
            logger.LogInformation("Bundle digest sha256:{Digest}", digest);

            if (!TryParseDetachedJws(signatureContent, out var encodedHeader, out var encodedSignature))
            {
                logger.LogError("Signature is not in detached JWS format.");
                Environment.ExitCode = 1;
                return;
            }

            var headerJson = Encoding.UTF8.GetString(Base64UrlDecode(encodedHeader));
            using var headerDocument = JsonDocument.Parse(headerJson);
            var header = headerDocument.RootElement;

            if (!header.TryGetProperty("b64", out var b64Element) || b64Element.GetBoolean())
            {
                logger.LogError("Detached JWS header must include '\"b64\": false'.");
                Environment.ExitCode = 1;
                return;
            }

            var algorithm = header.TryGetProperty("alg", out var algElement) ? algElement.GetString() : SignatureAlgorithms.Es256;
            if (string.IsNullOrWhiteSpace(algorithm))
            {
                algorithm = SignatureAlgorithms.Es256;
            }

            var providerHint = header.TryGetProperty("provider", out var providerElement)
                ? providerElement.GetString()
                : null;

            var keyId = header.TryGetProperty("kid", out var kidElement) ? kidElement.GetString() : null;
            if (string.IsNullOrWhiteSpace(keyId))
            {
                keyId = Path.GetFileNameWithoutExtension(keyPath);
                logger.LogWarning("JWS header missing 'kid'; using fallback key id {KeyId}.", keyId);
            }

            CryptoSigningKey signingKey;
            try
            {
                signingKey = CreateVerificationSigningKey(keyId!, algorithm!, providerHint, keyPem, keyPath);
            }
            catch (Exception ex) when (ex is InvalidOperationException or CryptographicException)
            {
                logger.LogError(ex, "Failed to load verification key material.");
                Environment.ExitCode = 1;
                return;
            }

            var providers = new List<ICryptoProvider>
            {
                new DefaultCryptoProvider()
            };

#if STELLAOPS_CRYPTO_SODIUM
            providers.Add(new LibsodiumCryptoProvider());
#endif

            foreach (var provider in providers)
            {
                if (provider.Supports(CryptoCapability.Verification, algorithm!))
                {
                    provider.UpsertSigningKey(signingKey);
                }
            }

            var preferredOrder = !string.IsNullOrWhiteSpace(providerHint)
                ? new[] { providerHint! }
                : Array.Empty<string>();
            var registry = new CryptoProviderRegistry(providers, preferredOrder);
            CryptoSignerResolution resolution;
            try
            {
                resolution = registry.ResolveSigner(
                    CryptoCapability.Verification,
                    algorithm!,
                    signingKey.Reference,
                    providerHint);
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "No crypto provider available for verification (algorithm {Algorithm}).", algorithm);
                Environment.ExitCode = 1;
                return;
            }

            var signingInputLength = encodedHeader.Length + 1 + bundleBytes.Length;
            var buffer = ArrayPool<byte>.Shared.Rent(signingInputLength);
            try
            {
                var headerBytes = Encoding.ASCII.GetBytes(encodedHeader);
                Buffer.BlockCopy(headerBytes, 0, buffer, 0, headerBytes.Length);
                buffer[headerBytes.Length] = (byte)'.';
                Buffer.BlockCopy(bundleBytes, 0, buffer, headerBytes.Length + 1, bundleBytes.Length);

                var signatureBytes = Base64UrlDecode(encodedSignature);
                var verified = await resolution.Signer.VerifyAsync(
                    new ReadOnlyMemory<byte>(buffer, 0, signingInputLength),
                    signatureBytes,
                    cancellationToken).ConfigureAwait(false);

                if (!verified)
                {
                    logger.LogError("Signature verification failed.");
                    Environment.ExitCode = 1;
                    return;
                }
            }
            finally
            {
                ArrayPool<byte>.Shared.Return(buffer);
            }

            if (!string.IsNullOrWhiteSpace(providerHint) && !string.Equals(providerHint, resolution.ProviderName, StringComparison.OrdinalIgnoreCase))
            {
                logger.LogWarning(
                    "Preferred provider '{Preferred}' unavailable; verification used '{Provider}'.",
                    providerHint,
                    resolution.ProviderName);
            }

            logger.LogInformation(
                "Signature verified using algorithm {Algorithm} via provider {Provider} (kid {KeyId}).",
                algorithm,
                resolution.ProviderName,
                signingKey.Reference.KeyId);

            if (verbose)
            {
                logger.LogInformation("JWS header: {Header}", headerJson);
            }
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Failed to verify revocation bundle.");
            Environment.ExitCode = 1;
        }
        finally
        {
            loggerFactory.Dispose();
        }
    }

    private static bool TryParseDetachedJws(string value, out string encodedHeader, out string encodedSignature)
    {
        encodedHeader = string.Empty;
        encodedSignature = string.Empty;

        if (string.IsNullOrWhiteSpace(value))
        {
            return false;
        }

        var parts = value.Split('.');
        if (parts.Length != 3)
        {
            return false;
        }

        encodedHeader = parts[0];
        encodedSignature = parts[2];
        return parts[1].Length == 0;
    }

    private static byte[] Base64UrlDecode(string value)
    {
        var normalized = value.Replace('-', '+').Replace('_', '/');
        var padding = normalized.Length % 4;
        if (padding == 2)
        {
            normalized += "==";
        }
        else if (padding == 3)
        {
            normalized += "=";
        }
        else if (padding == 1)
        {
            throw new FormatException("Invalid Base64Url value.");
        }

        return Convert.FromBase64String(normalized);
    }

    private static CryptoSigningKey CreateVerificationSigningKey(
        string keyId,
        string algorithm,
        string? providerHint,
        string keyPem,
        string keyPath)
    {
        if (string.IsNullOrWhiteSpace(keyPem))
        {
            throw new InvalidOperationException("Verification key PEM content is empty.");
        }

        using var ecdsa = ECDsa.Create();
        ecdsa.ImportFromPem(keyPem);

        var parameters = ecdsa.ExportParameters(includePrivateParameters: false);
        if (parameters.D is null || parameters.D.Length == 0)
        {
            parameters.D = new byte[] { 0x01 };
        }

        var metadata = new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase)
        {
            ["source"] = Path.GetFullPath(keyPath),
            ["verificationOnly"] = "true"
        };

        return new CryptoSigningKey(
            new CryptoKeyReference(keyId, providerHint),
            algorithm,
            in parameters,
            DateTimeOffset.UtcNow,
            metadata: metadata);
    }

    private static string FormatDuration(TimeSpan duration)
    {
        if (duration <= TimeSpan.Zero)
        {
            return "expired";
        }

        if (duration.TotalDays >= 1)
        {
            var days = (int)duration.TotalDays;
            var hours = duration.Hours;
            return hours > 0
                ? FormattableString.Invariant($"{days}d {hours}h")
                : FormattableString.Invariant($"{days}d");
        }

        if (duration.TotalHours >= 1)
        {
            return FormattableString.Invariant($"{(int)duration.TotalHours}h {duration.Minutes}m");
        }

        if (duration.TotalMinutes >= 1)
        {
            return FormattableString.Invariant($"{(int)duration.TotalMinutes}m {duration.Seconds}s");
        }

        return FormattableString.Invariant($"{duration.Seconds}s");
    }

    private static bool TryExtractJwtClaims(
        string accessToken,
        out Dictionary<string, string> claims,
        out DateTimeOffset? issuedAt,
        out DateTimeOffset? notBefore)
    {
        claims = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
        issuedAt = null;
        notBefore = null;

        if (string.IsNullOrWhiteSpace(accessToken))
        {
            return false;
        }

        var parts = accessToken.Split('.');
        if (parts.Length < 2)
        {
            return false;
        }

        if (!TryDecodeBase64Url(parts[1], out var payloadBytes))
        {
            return false;
        }

        try
        {
            using var document = JsonDocument.Parse(payloadBytes);
            foreach (var property in document.RootElement.EnumerateObject())
            {
                var value = FormatJsonValue(property.Value);
                claims[property.Name] = value;

                if (issuedAt is null && property.NameEquals("iat") && TryParseUnixSeconds(property.Value, out var parsedIat))
                {
                    issuedAt = parsedIat;
                }

                if (notBefore is null && property.NameEquals("nbf") && TryParseUnixSeconds(property.Value, out var parsedNbf))
                {
                    notBefore = parsedNbf;
                }
            }

            return true;
        }
        catch (JsonException)
        {
            claims.Clear();
            issuedAt = null;
            notBefore = null;
            return false;
        }
    }

    private static bool TryDecodeBase64Url(string value, out byte[] bytes)
    {
        bytes = Array.Empty<byte>();

        if (string.IsNullOrWhiteSpace(value))
        {
            return false;
        }

        var normalized = value.Replace('-', '+').Replace('_', '/');
        var padding = normalized.Length % 4;
        if (padding is 2 or 3)
        {
            normalized = normalized.PadRight(normalized.Length + (4 - padding), '=');
        }
        else if (padding == 1)
        {
            return false;
        }

        try
        {
            bytes = Convert.FromBase64String(normalized);
            return true;
        }
        catch (FormatException)
        {
            return false;
        }
    }

    private static string FormatJsonValue(JsonElement element)
    {
        return element.ValueKind switch
        {
            JsonValueKind.String => element.GetString() ?? string.Empty,
            JsonValueKind.Number => element.TryGetInt64(out var longValue)
                ? longValue.ToString(CultureInfo.InvariantCulture)
                : element.GetDouble().ToString(CultureInfo.InvariantCulture),
            JsonValueKind.True => "true",
            JsonValueKind.False => "false",
            JsonValueKind.Null => "null",
            JsonValueKind.Array => FormatArray(element),
            JsonValueKind.Object => element.GetRawText(),
            _ => element.GetRawText()
        };
    }

    private static string FormatArray(JsonElement array)
    {
        var values = new List<string>();
        foreach (var item in array.EnumerateArray())
        {
            values.Add(FormatJsonValue(item));
        }

        return string.Join(", ", values);
    }

    private static bool TryParseUnixSeconds(JsonElement element, out DateTimeOffset value)
    {
        value = default;

        if (element.ValueKind == JsonValueKind.Number)
        {
            if (element.TryGetInt64(out var seconds))
            {
                value = DateTimeOffset.FromUnixTimeSeconds(seconds);
                return true;
            }

            if (element.TryGetDouble(out var doubleValue))
            {
                value = DateTimeOffset.FromUnixTimeSeconds((long)doubleValue);
                return true;
            }
        }

        if (element.ValueKind == JsonValueKind.String)
        {
            var text = element.GetString();
            if (!string.IsNullOrWhiteSpace(text) && long.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out var seconds))
            {
                value = DateTimeOffset.FromUnixTimeSeconds(seconds);
                return true;
            }
        }

        return false;
    }

    private static List<string> CollectAdditionalClaims(Dictionary<string, string> claims)
    {
        var result = new List<string>();
        foreach (var pair in claims)
        {
            if (CommonClaimNames.Contains(pair.Key))
            {
                continue;
            }

            result.Add(FormattableString.Invariant($"{pair.Key}={pair.Value}"));
        }

        result.Sort(StringComparer.OrdinalIgnoreCase);
        return result;
    }

    private static readonly HashSet<string> CommonClaimNames = new(StringComparer.OrdinalIgnoreCase)
    {
        "aud",
        "client_id",
        "exp",
        "iat",
        "iss",
        "nbf",
        "scope",
        "scopes",
        "sub",
        "token_type",
        "jti"
    };

    private static async Task TriggerJobAsync(
        IBackendOperationsClient client,
        ILogger logger,
        string jobKind,
        IDictionary<string, object?> parameters,
        CancellationToken cancellationToken)
    {
        JobTriggerResult result = await client.TriggerJobAsync(jobKind, parameters, cancellationToken).ConfigureAwait(false);
        if (result.Success)
        {
            if (!string.IsNullOrWhiteSpace(result.Location))
            {
                logger.LogInformation("Job accepted. Track status at {Location}.", result.Location);
            }
            else if (result.Run is not null)
            {
                logger.LogInformation("Job accepted. RunId: {RunId} Status: {Status}", result.Run.RunId, result.Run.Status);
            }
            else
            {
                logger.LogInformation("Job accepted.");
            }

            Environment.ExitCode = 0;
        }
        else
        {
            logger.LogError("Job '{JobKind}' failed: {Message}", jobKind, result.Message);
            Environment.ExitCode = 1;
        }
    }
}
