using System.Security.Claims;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text.Json;
using System.Threading.RateLimiting;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Certificate;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Server.Kestrel.Https;
using Microsoft.Data.Sqlite;
using Microsoft.Extensions.Options;
using ServerMonitorManager.Control;
using ServerMonitorManager.Core;

const string AutomationSourceClaim = "smm:source_node_id";

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();
builder.Services.AddHealthChecks();
builder.Services.AddRateLimiter(options =>
{
    options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
    options.AddPolicy("enrollment", context => RateLimitPartition.GetFixedWindowLimiter(
        context.Connection.RemoteIpAddress?.ToString() ?? "unknown",
        _ => new FixedWindowRateLimiterOptions
        {
            PermitLimit = 10,
            Window = TimeSpan.FromMinutes(1),
            QueueLimit = 0,
            AutoReplenishment = true
        }));
    options.AddPolicy("password-login", context => RateLimitPartition.GetFixedWindowLimiter(
        context.Connection.RemoteIpAddress?.ToString() ?? "unknown",
        _ => new FixedWindowRateLimiterOptions
        {
            PermitLimit = 5,
            Window = TimeSpan.FromMinutes(1),
            QueueLimit = 0,
            AutoReplenishment = true
        }));
});
builder.Services.ConfigureHttpJsonOptions(options =>
    options.SerializerOptions.TypeInfoResolverChain.Insert(0, SmmJsonContext.Default));
builder.Services.AddOptions<ControlOptions>()
    .Bind(builder.Configuration.GetSection(ControlOptions.SectionName))
    .Validate(options =>
            !string.IsNullOrWhiteSpace(options.DatabasePath)
            && !string.IsNullOrWhiteSpace(options.CertificateAuthorityPath)
            && !string.IsNullOrWhiteSpace(options.HubHelperPath)
            && !string.IsNullOrWhiteSpace(options.PrivilegeEscalationPath)
            && !string.IsNullOrWhiteSpace(options.BackupDirectory)
            && options.HeartbeatSeconds is >= 10 and <= 300
            && options.MaxBufferedMetricAgeHours is >= 1 and <= 168
            && options.MetricRetentionHours is >= 24 and <= 8760
            && options.IdempotencyRetentionHours is >= 1 and <= 720
            && options.AuditRetentionDays is >= 1 and <= 3650
            && options.LinkRetentionDays is >= 1 and <= 3650
            && options.MaintenanceIntervalMinutes is >= 1 and <= 1440
            && options.LinkExpirationPollSeconds is >= 1 and <= 300
            && options.LinkReconciliationSeconds is >= 30 and <= 3600
            && options.BackupIntervalHours is >= 1 and <= 720
            && options.BackupRetentionCount is >= 1 and <= 100
            && options.ClientCertificateDays is >= 1 and <= 90,
        "Invalid Control paths, heartbeat, retention, maintenance, expiration, reconciliation, or backup settings.")
    .ValidateOnStart();
builder.Services.AddOptions<PasswordLoginOptions>()
    .Bind(builder.Configuration.GetSection(PasswordLoginOptions.SectionName));
builder.Services.AddSingleton(TimeProvider.System);
builder.Services.AddSingleton<ControlStore>();
builder.Services.AddSingleton<CertificateAuthority>();
builder.Services.AddSingleton<ControlEventBroker>();
builder.Services.AddSingleton<ILinkPolicyApplier, LinkPolicyApplier>();
builder.Services.AddSingleton<LinkService>();
builder.Services.AddSingleton<CertificateLifecycleService>();
builder.Services.AddSingleton<NodeEnrollmentService>();
builder.Services.AddSingleton<ControlBackupService>();
builder.Services.AddSingleton<PasswordSessionService>();
builder.Services.AddHostedService<LinkExpirationBackgroundService>();
builder.Services.AddHostedService<LinkReconciliationBackgroundService>();
builder.Services.AddHostedService<ControlMaintenanceBackgroundService>();
builder.Services.AddAuthentication(options =>
    {
        options.DefaultScheme = "Combined";
        options.DefaultAuthenticateScheme = "Combined";
        options.DefaultChallengeScheme = CertificateAuthenticationDefaults.AuthenticationScheme;
    })
    .AddPolicyScheme("Combined", "mTLS or Testing Password Session", options =>
    {
        options.ForwardDefaultSelector = context =>
        {
            if (context.Request.Headers.ContainsKey("X-Test-Role"))
            {
                return "TestCert";
            }
            if (context.Connection.ClientCertificate is not null)
            {
                return CertificateAuthenticationDefaults.AuthenticationScheme;
            }
            if (context.Request.Headers.ContainsKey("Authorization")
                || context.Request.Cookies.ContainsKey(PasswordSessionAuthenticationHandler.SessionCookieName))
            {
                return PasswordSessionAuthenticationHandler.SchemeName;
            }
            return CertificateAuthenticationDefaults.AuthenticationScheme;
        };
    })
    .AddCertificate(options =>
    {
        options.AllowedCertificateTypes = CertificateTypes.All;
        options.RevocationMode = X509RevocationMode.NoCheck;
        options.ValidateCertificateUse = true;
        options.ValidateValidityPeriod = true;
        options.Events = new CertificateAuthenticationEvents
        {
            OnChallenge = context =>
            {
                context.Response.StatusCode = StatusCodes.Status401Unauthorized;
                context.HandleResponse();
                return Task.CompletedTask;
            },
            OnCertificateValidated = async context =>
            {
                var store = context.HttpContext.RequestServices.GetRequiredService<ControlStore>();
                var identity = await store.ResolveIdentityAsync(context.ClientCertificate.Thumbprint);
                if (identity is null)
                {
                    context.Fail("The agent certificate is unknown, expired, or revoked.");
                    return;
                }

                var claims = new List<Claim>
                {
                    new(ClaimTypes.NameIdentifier, identity.Id),
                    new(ClaimTypes.Role, identity.Role)
                };
                if (identity.SourceNodeId is not null)
                {
                    claims.Add(new Claim(AutomationSourceClaim, identity.SourceNodeId));
                }
                context.Principal = new ClaimsPrincipal(new ClaimsIdentity(claims, context.Scheme.Name));
                context.Success();
            }
        };
    })
    .AddScheme<AuthenticationSchemeOptions, PasswordSessionAuthenticationHandler>(
        PasswordSessionAuthenticationHandler.SchemeName, _ => { });
builder.Services.AddOptions<CertificateAuthenticationOptions>(
        CertificateAuthenticationDefaults.AuthenticationScheme)
    .Configure<CertificateAuthority>((options, authority) =>
    {
        options.ChainTrustValidationMode = X509ChainTrustMode.CustomRootTrust;
        options.CustomTrustStore.Add(authority.PublicCertificate);
    });
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("Agent", policy => policy.RequireRole("Agent"));
    options.AddPolicy("Operator", policy => policy.RequireRole("Operator"));
    options.AddPolicy("Automation", policy => policy.RequireRole("Automation"));
});
builder.WebHost.ConfigureKestrel(options =>
{
    options.Limits.MaxRequestBodySize = 64 * 1024;
    options.ConfigureHttpsDefaults(https =>
        https.ClientCertificateMode = ClientCertificateMode.AllowCertificate);
});

var app = builder.Build();
app.UseExceptionHandler();
app.UseHsts();
app.UseRateLimiter();
app.UseAuthentication();
app.UseAuthorization();

var passwordOptions = builder.Configuration
    .GetSection(PasswordLoginOptions.SectionName)
    .Get<PasswordLoginOptions>() ?? new PasswordLoginOptions();
if (passwordOptions.EnabledForTesting)
{
    app.Logger.LogWarning(
        "SECURITY WARNING: Password login is enabled for testing purposes (Authentication:PasswordLogin:EnabledForTesting=true). Do not enable in production environments!");
}

var store = app.Services.GetRequiredService<ControlStore>();
var backupService = app.Services.GetRequiredService<ControlBackupService>();
if (args is ["backup-restore", var backupPath])
{
    await backupService.RestoreAsync(backupPath);
    Console.WriteLine("Control backup restored. Start the service and verify /healthz.");
    return 0;
}
await store.InitializeAsync();

if (args is ["backup-create"])
{
    var createdBackupPath = await backupService.CreateAsync(DateTimeOffset.UtcNow);
    Console.WriteLine(createdBackupPath);
    return 0;
}

if (args is ["token-create", var nodeId])
{
    if (!NodeIdValidator.IsValid(nodeId))
    {
        Console.Error.WriteLine("Node id must contain 1-63 lowercase letters, digits, or hyphens.");
        return 2;
    }

    Console.WriteLine(await store.CreateEnrollmentTokenAsync(nodeId, TimeSpan.FromMinutes(10)));
    return 0;
}

if (args is ["device-token-create", var deviceId])
{
    if (!NodeIdValidator.IsValid(deviceId))
    {
        Console.Error.WriteLine("Device id must contain 1-63 lowercase letters, digits, or hyphens.");
        return 2;
    }

    Console.WriteLine(await store.CreateDeviceEnrollmentTokenAsync(deviceId, TimeSpan.FromMinutes(10)));
    return 0;
}

if (args is ["automation-token-create", var automationId, var sourceNodeId])
{
    if (!NodeIdValidator.IsValid(automationId) || !NodeIdValidator.IsValid(sourceNodeId))
    {
        Console.Error.WriteLine("Automation and source Node ids must contain 1-63 lowercase letters, digits, or hyphens.");
        return 2;
    }

    var response = await store.CreateAutomationTokenAsync(
        new AutomationTokenCreateRequest(
            automationId, sourceNodeId, Guid.NewGuid().ToString()),
        "hub-cli",
        TimeSpan.FromMinutes(10));
    Console.WriteLine(JsonSerializer.Serialize(response, SmmJsonContext.Default.AutomationTokenResponse));
    return 0;
}

app.MapHealthChecks("/healthz").AllowAnonymous();

app.MapPost("/api/v1/enroll", async (
    EnrollmentRequest request,
    ControlStore controlStore,
    CertificateAuthority authority,
    CancellationToken cancellationToken) =>
{
    if (!NodeIdValidator.IsValid(request.NodeId)
        || string.IsNullOrWhiteSpace(request.Token)
        || string.IsNullOrWhiteSpace(request.CertificateSigningRequestPem)
        || !IdempotencyKeyValidator.IsValid(request.IdempotencyKey))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["request"] = ["Invalid enrollment request."]
        });
    }

    EnrollmentResponse? response;
    try
    {
        response = await controlStore.EnrollAsync(
            request,
            () => authority.IssueClientCertificate(request.NodeId, request.CertificateSigningRequestPem),
            cancellationToken);
    }
    catch (IdempotencyConflictException)
    {
        return Results.Conflict(new ProblemDetails
        {
            Title = "Idempotency key conflict",
            Status = StatusCodes.Status409Conflict
        });
    }
    catch (Exception exception) when (exception is CryptographicException or InvalidOperationException)
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["certificateSigningRequestPem"] = ["Invalid certificate signing request."]
        });
    }

    return response is null
        ? Results.Unauthorized()
        : Results.Ok(response);
}).AllowAnonymous().RequireRateLimiting("enrollment");

app.MapPost("/api/v1/device-enroll", async (
    DeviceEnrollmentRequest request,
    ControlStore controlStore,
    CertificateAuthority authority,
    CancellationToken cancellationToken) =>
{
    if (!NodeIdValidator.IsValid(request.DeviceId)
        || string.IsNullOrWhiteSpace(request.Token)
        || string.IsNullOrWhiteSpace(request.CertificateSigningRequestPem)
        || !IdempotencyKeyValidator.IsValid(request.IdempotencyKey))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["request"] = ["Invalid device enrollment request."]
        });
    }

    try
    {
        var response = await controlStore.EnrollDeviceAsync(
            request,
            () => authority.IssueClientCertificate(request.DeviceId, request.CertificateSigningRequestPem),
            cancellationToken);
        return response is null ? Results.Unauthorized() : Results.Ok(response);
    }
    catch (IdempotencyConflictException)
    {
        return Results.Conflict(new ProblemDetails
        {
            Title = "Idempotency key conflict",
            Status = StatusCodes.Status409Conflict
        });
    }
    catch (Exception exception) when (exception is CryptographicException or InvalidOperationException)
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["certificateSigningRequestPem"] = ["Invalid certificate signing request."]
        });
    }
}).AllowAnonymous().RequireRateLimiting("enrollment");

app.MapPost("/api/v1/automation-enroll", async (
    AutomationEnrollmentRequest request,
    ControlStore controlStore,
    CertificateAuthority authority,
    CancellationToken cancellationToken) =>
{
    if (!NodeIdValidator.IsValid(request.AutomationId)
        || string.IsNullOrWhiteSpace(request.Token)
        || string.IsNullOrWhiteSpace(request.CertificateSigningRequestPem)
        || !IdempotencyKeyValidator.IsValid(request.IdempotencyKey))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["request"] = ["Invalid automation enrollment request."]
        });
    }

    try
    {
        var response = await controlStore.EnrollAutomationAsync(
            request,
            () => authority.IssueClientCertificate(
                request.AutomationId, request.CertificateSigningRequestPem),
            cancellationToken);
        return response is null ? Results.Unauthorized() : Results.Ok(response);
    }
    catch (IdempotencyConflictException)
    {
        return Results.Conflict(new ProblemDetails
        {
            Title = "Idempotency key conflict",
            Status = StatusCodes.Status409Conflict
        });
    }
    catch (Exception exception) when (exception is CryptographicException or InvalidOperationException)
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["certificateSigningRequestPem"] = ["Invalid certificate signing request."]
        });
    }
}).AllowAnonymous().RequireRateLimiting("enrollment");

var agents = app.MapGroup("/api/v1/agents").RequireAuthorization("Agent");
agents.MapPost("/heartbeat", async (
    AgentHeartbeat heartbeat,
    HttpContext context,
    ControlStore controlStore,
    LinkService linkService,
    IOptions<ControlOptions> options,
    CancellationToken cancellationToken) =>
{
    if (!NodeIdValidator.IsValid(heartbeat.NodeId)
        || !IdempotencyKeyValidator.IsValid(heartbeat.IdempotencyKey)
        || heartbeat.SentAt < DateTimeOffset.UtcNow.AddHours(-options.Value.MaxBufferedMetricAgeHours)
        || heartbeat.SentAt > DateTimeOffset.UtcNow.AddMinutes(1))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["heartbeat"] = ["Invalid or stale heartbeat."]
        });
    }

    var certificate = await context.Connection.GetClientCertificateAsync(cancellationToken);
    if (certificate is null)
    {
        return Results.Unauthorized();
    }

    if (!await controlStore.IsCertificateForNodeAsync(
            certificate.Thumbprint,
            heartbeat.NodeId,
            cancellationToken))
    {
        return Results.Forbid();
    }

    try
    {
        var mutation = await controlStore.RecordHeartbeatAsync(
            heartbeat,
            options.Value.HeartbeatSeconds,
            cancellationToken);
        if (mutation.RequiresReconciliation)
        {
            var reconciliation = await linkService.ReconcileLinksForNodeAsync(
                heartbeat.NodeId, cancellationToken);
            if (reconciliation.Failed == 0)
            {
                await controlStore.CompleteAgentReconciliationAsync(
                    heartbeat.NodeId, cancellationToken);
            }
        }
        var broker = context.RequestServices.GetRequiredService<ControlEventBroker>();
        broker.Publish(
            "agent.heartbeat",
            heartbeat.NodeId,
            JsonSerializer.Serialize(heartbeat, SmmJsonContext.Default.AgentHeartbeat));
        return Results.Ok(mutation.Response);
    }
    catch (IdempotencyConflictException)
    {
        return Results.Conflict(new ProblemDetails
        {
            Title = "Idempotency key conflict",
            Status = StatusCodes.Status409Conflict
        });
    }
});
agents.MapPost("/certificate/renew", async (
    CertificateRenewalRequest request,
    HttpContext context,
    CertificateLifecycleService lifecycle,
    CancellationToken cancellationToken) =>
{
    var nodeId = context.User.FindFirstValue(ClaimTypes.NameIdentifier);
    if (string.IsNullOrWhiteSpace(nodeId)
        || !NodeIdValidator.IsValid(nodeId)
        || !IdempotencyKeyValidator.IsValid(request.IdempotencyKey))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["request"] = ["Invalid node id or idempotency key."]
        });
    }

    try
    {
        var issued = await lifecycle.RenewAgentCertificateAsync(
            nodeId, request, nodeId, cancellationToken);
        return Results.Ok(new CertificateRenewalResponse(
            nodeId, issued.CertificatePem, issued.CertificateAuthorityPem, issued.ExpiresAt));
    }
    catch (InvalidOperationException exception)
    {
        return Results.Conflict(new ProblemDetails { Title = exception.Message });
    }
});
agents.MapGet("/provisioning/jobs/next", async (
    HttpContext context,
    ControlStore controlStore,
    CancellationToken cancellationToken) =>
{
    var nodeId = context.User.FindFirstValue(ClaimTypes.NameIdentifier);
    if (string.IsNullOrWhiteSpace(nodeId) || !NodeIdValidator.IsValid(nodeId))
    {
        return Results.Forbid();
    }

    var job = await controlStore.ClaimNextProvisioningJobAsync(nodeId, cancellationToken);
    return job is null ? Results.NoContent() : Results.Ok(job);
});
agents.MapPost("/provisioning/jobs/{id}/progress", async (
    string id,
    ProvisioningJobProgressRequest request,
    HttpContext context,
    ControlStore controlStore,
    CancellationToken cancellationToken) =>
{
    var nodeId = context.User.FindFirstValue(ClaimTypes.NameIdentifier);
    if (string.IsNullOrWhiteSpace(nodeId)
        || !NodeIdValidator.IsValid(nodeId)
        || !ProvisioningJobValidator.IsValidId(id)
        || !ProvisioningJobValidator.IsValid(request))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["provisioningProgress"] =
                ["Invalid job id, state, progress, step, event code, message, or idempotency key."]
        });
    }

    try
    {
        var job = await controlStore.ReportProvisioningProgressAsync(
            nodeId, id, request, cancellationToken);
        return job is null ? Results.NotFound() : Results.Ok(job);
    }
    catch (IdempotencyConflictException)
    {
        return Results.Conflict(new ProblemDetails { Title = "Idempotency key conflict" });
    }
    catch (ProvisioningTransitionException exception)
    {
        return Results.Conflict(new ProblemDetails { Title = exception.Message });
    }
});
agents.MapPost("/provisioning/jobs/{id}/preflight-facts", async (
    string id,
    ProvisioningPreflightReportRequest request,
    HttpContext context,
    ControlStore controlStore,
    CancellationToken cancellationToken) =>
{
    var nodeId = context.User.FindFirstValue(ClaimTypes.NameIdentifier);
    if (string.IsNullOrWhiteSpace(nodeId)
        || !NodeIdValidator.IsValid(nodeId)
        || !ProvisioningJobValidator.IsValidId(id)
        || !ProvisioningJobValidator.IsValid(request))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["preflightFacts"] = ["Invalid job id, facts, observation time, or idempotency key."]
        });
    }

    try
    {
        var facts = await controlStore.RecordPreflightFactsAsync(
            nodeId, id, request, cancellationToken);
        return facts is null ? Results.NotFound() : Results.Ok(facts);
    }
    catch (IdempotencyConflictException)
    {
        return Results.Conflict(new ProblemDetails { Title = "Idempotency key conflict" });
    }
    catch (ProvisioningTransitionException exception)
    {
        return Results.Conflict(new ProblemDetails { Title = exception.Message });
    }
});
agents.MapPost("/provisioning/jobs/{id}/base-install-plan", async (
    string id,
    SystemBaseInstallPlanReportRequest request,
    HttpContext context,
    ControlStore controlStore,
    CancellationToken cancellationToken) =>
{
    var nodeId = context.User.FindFirstValue(ClaimTypes.NameIdentifier);
    if (string.IsNullOrWhiteSpace(nodeId)
        || !NodeIdValidator.IsValid(nodeId)
        || !ProvisioningJobValidator.IsValidId(id)
        || !ProvisioningJobValidator.IsValid(request))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["baseInstallPlan"] = ["Invalid job id, plan, or idempotency key."]
        });
    }

    try
    {
        var plan = await controlStore.RecordBaseInstallPlanAsync(
            nodeId, id, request, cancellationToken);
        return plan is null ? Results.NotFound() : Results.Ok(plan);
    }
    catch (IdempotencyConflictException)
    {
        return Results.Conflict(new ProblemDetails { Title = "Idempotency key conflict" });
    }
    catch (ProvisioningTransitionException exception)
    {
        return Results.Conflict(new ProblemDetails { Title = exception.Message });
    }
    catch (ProvisioningPlanValidationException exception)
    {
        return Results.BadRequest(new ProblemDetails { Title = exception.Message });
    }
});
agents.MapPost("/provisioning/jobs/{id}/execution-grant", async (
    string id,
    ProvisioningExecutionGrantRequest request,
    HttpContext context,
    ControlStore controlStore,
    CertificateAuthority authority,
    TimeProvider timeProvider,
    CancellationToken cancellationToken) =>
{
    var nodeId = context.User.FindFirstValue(ClaimTypes.NameIdentifier);
    if (string.IsNullOrWhiteSpace(nodeId)
        || !NodeIdValidator.IsValid(nodeId)
        || !ProvisioningJobValidator.IsValidId(id)
        || !ProvisioningJobValidator.IsValid(request))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["executionGrant"] = ["Invalid job id or idempotency key."]
        });
    }
    try
    {
        var grant = await controlStore.IssueBaseInstallExecutionGrantAsync(
            nodeId,
            id,
            request,
            (job, plan) => authority.SignProvisioningExecutionGrant(
                job, plan, timeProvider.GetUtcNow(), TimeSpan.FromMinutes(2)),
            cancellationToken);
        return grant is null ? Results.NotFound() : Results.Ok(grant);
    }
    catch (IdempotencyConflictException)
    {
        return Results.Conflict(new ProblemDetails { Title = "Idempotency key conflict" });
    }
    catch (ProvisioningTransitionException exception)
    {
        return Results.Conflict(new ProblemDetails { Title = exception.Message });
    }
});

var auth = app.MapGroup("/api/v1/auth");
auth.MapGet("/status", (IOptionsMonitor<PasswordLoginOptions> options) =>
    Results.Ok(new PasswordLoginStatusResponse(options.CurrentValue.EnabledForTesting)));

auth.MapPost("/login", async (
    PasswordLoginRequest request,
    HttpContext context,
    PasswordSessionService sessionService,
    IOptionsMonitor<PasswordLoginOptions> options,
    CancellationToken cancellationToken) =>
{
    if (!options.CurrentValue.EnabledForTesting)
    {
        return Results.NotFound(new ProblemDetails
        {
            Title = "Password login is disabled for testing.",
            Status = StatusCodes.Status404NotFound
        });
    }

    if (string.IsNullOrWhiteSpace(request.Username) || string.IsNullOrWhiteSpace(request.Password))
    {
        PasswordHasher.PerformDummyVerification(request.Password);
        await Task.Delay(500, cancellationToken);
        return Results.Unauthorized();
    }

    var session = sessionService.AuthenticateAndCreateSession(request.Username, request.Password);
    if (session is null)
    {
        await Task.Delay(500, cancellationToken);
        return Results.Unauthorized();
    }

    context.Response.Cookies.Append(
        PasswordSessionAuthenticationHandler.SessionCookieName,
        session.Token,
        new CookieOptions
        {
            HttpOnly = true,
            Secure = true,
            SameSite = SameSiteMode.Strict,
            Expires = session.ExpiresAt,
            Path = "/"
        });

    return Results.Ok(session);
}).RequireRateLimiting("password-login");

auth.MapPost("/logout", (
    HttpContext context,
    PasswordSessionService sessionService) =>
{
    string? token = null;
    if (context.Request.Headers.TryGetValue("Authorization", out var authHeader)
        && !string.IsNullOrWhiteSpace(authHeader))
    {
        var headerStr = authHeader.ToString();
        if (headerStr.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
        {
            token = headerStr["Bearer ".Length..].Trim();
        }
    }

    if (string.IsNullOrWhiteSpace(token)
        && context.Request.Cookies.TryGetValue(PasswordSessionAuthenticationHandler.SessionCookieName, out var cookieVal))
    {
        token = cookieVal;
    }

    sessionService.RevokeSession(token);
    context.Response.Cookies.Delete(
        PasswordSessionAuthenticationHandler.SessionCookieName,
        new CookieOptions
        {
            Path = "/",
            Secure = true,
            SameSite = SameSiteMode.Strict
        });

    return Results.NoContent();
});

var console = app.MapGroup("/");
if (!passwordOptions.EnabledForTesting)
{
    console.RequireAuthorization("Operator");
}
console.MapGet("/", (IWebHostEnvironment env) => GetWebConsoleAsset(env, "index.html", "text/html; charset=utf-8"));
console.MapGet("/index.html", (IWebHostEnvironment env) => GetWebConsoleAsset(env, "index.html", "text/html; charset=utf-8"));
console.MapGet("/style.css", (IWebHostEnvironment env) => GetWebConsoleAsset(env, "style.css", "text/css; charset=utf-8"));
console.MapGet("/app.js", (IWebHostEnvironment env) => GetWebConsoleAsset(env, "app.js", "application/javascript; charset=utf-8"));
console.MapGet("/console", (IWebHostEnvironment env) => GetWebConsoleAsset(env, "index.html", "text/html; charset=utf-8"));

var control = app.MapGroup("/api/v1/control").RequireAuthorization("Operator");
control.MapPost("/certificates/renew", async (
    CertificateRenewalRequest request,
    HttpContext context,
    CertificateLifecycleService lifecycle,
    CancellationToken cancellationToken) =>
{
    var deviceId = context.User.FindFirstValue(ClaimTypes.NameIdentifier);
    if (string.IsNullOrWhiteSpace(deviceId)
        || !NodeIdValidator.IsValid(deviceId)
        || !IdempotencyKeyValidator.IsValid(request.IdempotencyKey))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["request"] = ["Invalid device id or idempotency key."]
        });
    }

    try
    {
        var issued = await lifecycle.RenewDeviceCertificateAsync(
            deviceId, request, deviceId, cancellationToken);
        return Results.Ok(new CertificateRenewalResponse(
            deviceId, issued.CertificatePem, issued.CertificateAuthorityPem, issued.ExpiresAt));
    }
    catch (InvalidOperationException exception)
    {
        return Results.Conflict(new ProblemDetails { Title = exception.Message });
    }
});
control.MapPost("/agents/{nodeId}/enrollment-code", async (
    string nodeId,
    HttpContext context,
    NodeEnrollmentService enrollmentService,
    CancellationToken cancellationToken) =>
{
    if (!NodeIdValidator.IsValid(nodeId))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["nodeId"] = ["Node id must contain 1-63 lowercase letters, digits, or hyphens."]
        });
    }

    var actor = context.User.FindFirstValue(ClaimTypes.NameIdentifier) ?? "unknown";
    try
    {
        var response = await enrollmentService.CreateEnrollmentCodeAsync(
            nodeId, actor, cancellationToken);
        return Results.Ok(response);
    }
    catch (InvalidOperationException exception)
    {
        return Results.Conflict(new ProblemDetails { Title = exception.Message });
    }
}).RequireRateLimiting("enrollment");
control.MapGet("/agents", async (ControlStore controlStore, CancellationToken cancellationToken) =>
    Results.Ok((await controlStore.ListAgentsAsync(cancellationToken)).ToArray()));
control.MapGet("/provisioning/catalogs/system-base-install/1", () =>
    Results.Ok(SystemBaseInstallCatalogDefinition.Create()));
control.MapGet("/agents/{nodeId}/facts/preflight", async (
    string nodeId,
    ControlStore controlStore,
    CancellationToken cancellationToken) =>
{
    if (!NodeIdValidator.IsValid(nodeId))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["nodeId"] = ["Invalid node id."]
        });
    }
    var facts = await controlStore.GetPreflightFactsAsync(nodeId, cancellationToken);
    return facts is null ? Results.NotFound() : Results.Ok(facts);
});
control.MapPut("/agents/{nodeId}/desired/preflight", async (
    string nodeId,
    PreflightDesiredStateUpdateRequest request,
    HttpContext context,
    ControlStore controlStore,
    CancellationToken cancellationToken) =>
{
    if (!NodeIdValidator.IsValid(nodeId) || !PreflightDesiredStateValidator.IsValid(request))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["preflightDesiredState"] =
                ["Invalid schema, requirements, architectures, audit reason, or idempotency key."]
        });
    }
    try
    {
        var actor = context.User.FindFirstValue(ClaimTypes.NameIdentifier)!;
        var desired = await controlStore.SetPreflightDesiredStateAsync(
            nodeId, request, actor, cancellationToken);
        return Results.Ok(desired);
    }
    catch (IdempotencyConflictException)
    {
        return Results.Conflict(new ProblemDetails { Title = "Idempotency key conflict" });
    }
    catch (ProvisioningNodeNotFoundException)
    {
        return Results.NotFound();
    }
});
control.MapGet("/agents/{nodeId}/drift/preflight", async (
    string nodeId,
    ControlStore controlStore,
    CancellationToken cancellationToken) =>
{
    if (!NodeIdValidator.IsValid(nodeId))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["nodeId"] = ["Invalid node id."]
        });
    }
    var assessment = await controlStore.AssessPreflightDriftAsync(nodeId, cancellationToken);
    return assessment is null ? Results.NotFound() : Results.Ok(assessment);
});
control.MapPost("/agents/{nodeId}/provisioning/jobs", async (
    string nodeId,
    ProvisioningJobCreateRequest request,
    HttpContext context,
    ControlStore controlStore,
    CancellationToken cancellationToken) =>
{
    if (!NodeIdValidator.IsValid(nodeId) || !ProvisioningJobValidator.IsValid(request))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["provisioningJob"] =
                ["Invalid node id, action schema, parameters, TTL, audit reason, or idempotency key."]
        });
    }

    try
    {
        var actor = context.User.FindFirstValue(ClaimTypes.NameIdentifier)!;
        var job = await controlStore.CreateProvisioningJobAsync(
            nodeId, request, actor, cancellationToken);
        return Results.Created($"/api/v1/control/provisioning/jobs/{job.Id}", job);
    }
    catch (IdempotencyConflictException)
    {
        return Results.Conflict(new ProblemDetails { Title = "Idempotency key conflict" });
    }
    catch (ProvisioningNodeNotFoundException)
    {
        return Results.NotFound();
    }
    catch (SqliteException exception) when (exception.SqliteErrorCode == 19)
    {
        return Results.Conflict(new ProblemDetails
        {
            Title = "The node already has an incompatible active provisioning job."
        });
    }
});
control.MapGet("/provisioning/jobs/{id}", async (
    string id,
    ControlStore controlStore,
    CancellationToken cancellationToken) =>
{
    if (!ProvisioningJobValidator.IsValidId(id))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["provisioningJob"] = ["Invalid provisioning job id."]
        });
    }
    var job = await controlStore.GetProvisioningJobAsync(id, cancellationToken);
    return job is null ? Results.NotFound() : Results.Ok(job);
});
control.MapGet("/provisioning/jobs/{id}/plan", async (
    string id,
    ControlStore controlStore,
    CancellationToken cancellationToken) =>
{
    if (!ProvisioningJobValidator.IsValidId(id))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["baseInstallPlan"] = ["Invalid provisioning job id."]
        });
    }
    var plan = await controlStore.GetBaseInstallPlanAsync(id, cancellationToken);
    return plan is null ? Results.NotFound() : Results.Ok(plan);
});
control.MapGet("/provisioning/jobs/{id}/events", async (
    string id,
    int? limit,
    ControlStore controlStore,
    CancellationToken cancellationToken) =>
{
    if (!ProvisioningJobValidator.IsValidId(id) || limit is < 1 or > 200)
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["provisioningEvents"] = ["Invalid provisioning job id or limit (1-200)."]
        });
    }
    var events = await controlStore.ListProvisioningEventsAsync(
        id, limit ?? 100, cancellationToken);
    return events is null ? Results.NotFound() : Results.Ok(events.ToArray());
});
control.MapPost("/provisioning/jobs/{id}/confirm", async (
    string id,
    ProvisioningJobCommandRequest request,
    HttpContext context,
    ControlStore controlStore,
    CancellationToken cancellationToken) =>
    await ChangeProvisioningJobAsync(
        id, request, context, controlStore, confirm: true, cancellationToken));
control.MapPost("/provisioning/jobs/{id}/cancel", async (
    string id,
    ProvisioningJobCommandRequest request,
    HttpContext context,
    ControlStore controlStore,
    CancellationToken cancellationToken) =>
    await ChangeProvisioningJobAsync(
        id, request, context, controlStore, confirm: false, cancellationToken));
control.MapPost("/provisioning/jobs/{id}/retry", async (
    string id,
    ProvisioningJobCommandRequest request,
    HttpContext context,
    ControlStore controlStore,
    CancellationToken cancellationToken) =>
{
    if (!ProvisioningJobValidator.IsValidId(id)
        || !ProvisioningJobValidator.IsValid(request))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["provisioningJob"] = ["Invalid job id, reason, or idempotency key."]
        });
    }
    try
    {
        var actor = context.User.FindFirstValue(ClaimTypes.NameIdentifier)!;
        var job = await controlStore.RetryProvisioningJobAsync(
            id, request, actor, cancellationToken);
        return job is null ? Results.NotFound() : Results.Ok(job);
    }
    catch (IdempotencyConflictException)
    {
        return Results.Conflict(new ProblemDetails { Title = "Idempotency key conflict" });
    }
    catch (ProvisioningTransitionException exception)
    {
        return Results.Conflict(new ProblemDetails { Title = exception.Message });
    }
});
control.MapPost("/provisioning/jobs/{id}/rollback", async (
    string id,
    ProvisioningJobCommandRequest request,
    HttpContext context,
    ControlStore controlStore,
    CancellationToken cancellationToken) =>
{
    if (!ProvisioningJobValidator.IsValidId(id)
        || !ProvisioningJobValidator.IsValid(request))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["provisioningJob"] = ["Invalid job id, reason, or idempotency key."]
        });
    }
    try
    {
        var actor = context.User.FindFirstValue(ClaimTypes.NameIdentifier)!;
        var job = await controlStore.StartProvisioningRollbackAsync(
            id, request, actor, cancellationToken);
        return job is null ? Results.NotFound() : Results.Ok(job);
    }
    catch (IdempotencyConflictException)
    {
        return Results.Conflict(new ProblemDetails { Title = "Idempotency key conflict" });
    }
    catch (ProvisioningTransitionException exception)
    {
        return Results.Conflict(new ProblemDetails { Title = exception.Message });
    }
});
control.MapPost("/automations/token", async (
    AutomationTokenCreateRequest request,
    HttpContext context,
    ControlStore controlStore,
    CancellationToken cancellationToken) =>
{
    if (!NodeIdValidator.IsValid(request.AutomationId)
        || !NodeIdValidator.IsValid(request.SourceNodeId)
        || !IdempotencyKeyValidator.IsValid(request.IdempotencyKey))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["automation"] = ["Invalid automation id, source Node id, or idempotency key."]
        });
    }

    try
    {
        var actor = context.User.FindFirstValue(ClaimTypes.NameIdentifier)!;
        return Results.Ok(await controlStore.CreateAutomationTokenAsync(
            request, actor, TimeSpan.FromMinutes(10), cancellationToken));
    }
    catch (IdempotencyConflictException)
    {
        return Results.Conflict(new ProblemDetails { Title = "Idempotency key conflict" });
    }
    catch (InvalidOperationException exception)
    {
        return Results.BadRequest(new ProblemDetails { Title = exception.Message });
    }
});
control.MapPost("/agents/{nodeId}/reenroll", async (
    string nodeId,
    CertificateReenrollmentRequest request,
    HttpContext context,
    CertificateLifecycleService lifecycle,
    CancellationToken cancellationToken) =>
{
    if (!NodeIdValidator.IsValid(nodeId) || !CertificateReenrollmentValidator.IsValid(request))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["certificate"] = ["Invalid node id, reason, or idempotency key."]
        });
    }

    try
    {
        var actor = context.User.FindFirstValue(ClaimTypes.NameIdentifier)!;
        var ticket = await lifecycle.ReenrollAgentAsync(nodeId, request, actor, cancellationToken);
        return ticket is null ? Results.NotFound() : Results.Ok(ticket);
    }
    catch (IdempotencyConflictException)
    {
        return Results.Conflict(new ProblemDetails { Title = "Idempotency key conflict" });
    }
});
control.MapPost("/devices/{deviceId}/reenroll", async (
    string deviceId,
    CertificateReenrollmentRequest request,
    HttpContext context,
    CertificateLifecycleService lifecycle,
    CancellationToken cancellationToken) =>
{
    if (!NodeIdValidator.IsValid(deviceId) || !CertificateReenrollmentValidator.IsValid(request))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["certificate"] = ["Invalid device id, reason, or idempotency key."]
        });
    }

    try
    {
        var actor = context.User.FindFirstValue(ClaimTypes.NameIdentifier)!;
        if (string.Equals(actor, deviceId, StringComparison.Ordinal))
        {
            return Results.BadRequest(new ProblemDetails
            {
                Title = "An Operator cannot revoke its own certificate. Use another Operator or the local Hub CLI."
            });
        }
        var ticket = await lifecycle.ReenrollDeviceAsync(deviceId, request, actor, cancellationToken);
        return ticket is null ? Results.NotFound() : Results.Ok(ticket);
    }
    catch (IdempotencyConflictException)
    {
        return Results.Conflict(new ProblemDetails { Title = "Idempotency key conflict" });
    }
});
control.MapGet("/links", async (ControlStore controlStore, CancellationToken cancellationToken) =>
    Results.Ok((await controlStore.ListLinksAsync(cancellationToken)).ToArray()));
control.MapPost("/links", async (
    LinkPolicyCreateRequest request,
    HttpContext context,
    LinkService linkService,
    CancellationToken cancellationToken) =>
{
    if (!LinkPolicyValidator.IsValid(request))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["link"] = ["Invalid source, target, protocol, port, TTL, reason, or idempotency key."]
        });
    }
    var actor = context.User.FindFirstValue(ClaimTypes.NameIdentifier)!;
    try
    {
        var link = await linkService.CreateAsync(request, actor, cancellationToken);
        return Results.Created($"/api/v1/control/links/{link.Id}", link);
    }
    catch (IdempotencyConflictException)
    {
        return Results.Conflict(new ProblemDetails { Title = "Idempotency key conflict" });
    }
    catch (SqliteException exception) when (exception.SqliteErrorCode == 19)
    {
        return Results.Conflict(new ProblemDetails { Title = "An active Link already exists." });
    }
    catch (InvalidOperationException exception)
    {
        return Results.BadRequest(new ProblemDetails { Title = exception.Message });
    }
});
control.MapPost("/links/{id}/disable", async (
    string id,
    LinkPolicyDisableRequest request,
    HttpContext context,
    LinkService linkService,
    CancellationToken cancellationToken) =>
{
    if (id.Length != 32 || !Guid.TryParseExact(id, "N", out _)
        || !IdempotencyKeyValidator.IsValid(request.IdempotencyKey))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["link"] = ["Invalid Link id or idempotency key."]
        });
    }
    var actor = context.User.FindFirstValue(ClaimTypes.NameIdentifier)!;
    try
    {
        var link = await linkService.DisableAsync(id, request, actor, cancellationToken);
        return link is null ? Results.NotFound() : Results.Ok(link);
    }
    catch (IdempotencyConflictException)
    {
        return Results.Conflict(new ProblemDetails { Title = "Idempotency key conflict" });
    }
});
control.MapGet("/events", async (HttpContext context, ControlEventBroker broker) =>
{
    context.Response.ContentType = "application/x-ndjson";
    context.Response.Headers.CacheControl = "no-store";
    using var subscription = broker.Subscribe();
    await foreach (var controlEvent in subscription.Reader.ReadAllAsync(context.RequestAborted))
    {
        await JsonSerializer.SerializeAsync(
            context.Response.Body,
            controlEvent,
            SmmJsonContext.Default.ControlEvent,
            context.RequestAborted);
        await context.Response.WriteAsync("\n", context.RequestAborted);
        await context.Response.Body.FlushAsync(context.RequestAborted);
    }
});

var automation = app.MapGroup("/api/v1/automation").RequireAuthorization("Automation");
automation.MapGet("/links", async (
    HttpContext context,
    ControlStore controlStore,
    CancellationToken cancellationToken) =>
{
    var sourceNodeId = context.User.FindFirstValue(AutomationSourceClaim);
    if (string.IsNullOrWhiteSpace(sourceNodeId))
    {
        return Results.Forbid();
    }

    var grants = (await controlStore.ListEffectiveLinksForNodeAsync(sourceNodeId, cancellationToken))
        .Where(link => string.Equals(link.SourceNodeId, sourceNodeId, StringComparison.Ordinal))
        .Select(link => new AutomationLinkGrant(
            link.TargetNodeId,
            link.Protocol,
            link.Port,
            link.DesiredState,
            link.ActualState,
            link.Version,
            link.ExpiresAt))
        .ToArray();
    return Results.Ok(grants);
});

await app.RunAsync();
return 0;

static IResult GetWebConsoleAsset(IWebHostEnvironment env, string fileName, string contentType)
{
    var webRoot = env.WebRootPath;
    if (string.IsNullOrWhiteSpace(webRoot))
    {
        webRoot = Path.Combine(AppContext.BaseDirectory, "wwwroot");
    }

    var filePath = Path.Combine(webRoot, fileName);
    if (File.Exists(filePath))
    {
        return Results.File(filePath, contentType);
    }

    var assembly = typeof(Program).Assembly;
    var resourceName = assembly.GetManifestResourceNames()
        .FirstOrDefault(name => name.EndsWith(fileName, StringComparison.OrdinalIgnoreCase));

    if (resourceName is not null)
    {
        var stream = assembly.GetManifestResourceStream(resourceName);
        if (stream is not null)
        {
            return Results.Stream(stream, contentType);
        }
    }

    return Results.NotFound();
}

static async Task<IResult> ChangeProvisioningJobAsync(
    string id,
    ProvisioningJobCommandRequest request,
    HttpContext context,
    ControlStore controlStore,
    bool confirm,
    CancellationToken cancellationToken)
{
    if (!ProvisioningJobValidator.IsValidId(id)
        || !ProvisioningJobValidator.IsValid(request))
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["provisioningJob"] = ["Invalid job id, reason, or idempotency key."]
        });
    }

    try
    {
        var actor = context.User.FindFirstValue(ClaimTypes.NameIdentifier)!;
        var job = confirm
            ? await controlStore.ConfirmProvisioningJobAsync(id, request, actor, cancellationToken)
            : await controlStore.CancelProvisioningJobAsync(id, request, actor, cancellationToken);
        return job is null ? Results.NotFound() : Results.Ok(job);
    }
    catch (IdempotencyConflictException)
    {
        return Results.Conflict(new ProblemDetails { Title = "Idempotency key conflict" });
    }
    catch (ProvisioningTransitionException exception)
    {
        return Results.Conflict(new ProblemDetails { Title = exception.Message });
    }
}

public partial class Program;

internal static class NodeIdValidator
{
    public static bool IsValid(string value)
        => value.Length is >= 1 and <= 63
           && value.All(character => character is >= 'a' and <= 'z' or >= '0' and <= '9' or '-');
}

internal static class IdempotencyKeyValidator
{
    public static bool IsValid(string value)
        => Guid.TryParse(value, out _);
}

internal static class LinkPolicyValidator
{
    public static bool IsValid(LinkPolicyCreateRequest request)
        => NodeIdValidator.IsValid(request.SourceNodeId)
           && NodeIdValidator.IsValid(request.TargetNodeId)
           && request.SourceNodeId != request.TargetNodeId
           && request.Protocol is "tcp" or "udp"
           && request.Port is >= 1 and <= 65535
           && request.TtlMinutes is >= 0 and <= 525600
           && request.Reason.Length <= 256
           && IdempotencyKeyValidator.IsValid(request.IdempotencyKey);
}

internal static class CertificateReenrollmentValidator
{
    public static bool IsValid(CertificateReenrollmentRequest request)
        => request.Reason.Length is >= 1 and <= 200
           && IdempotencyKeyValidator.IsValid(request.IdempotencyKey);
}

internal static class ProvisioningJobValidator
{
    private const int MaximumParametersBytes = 16 * 1024;

    public static bool IsValid(ProvisioningJobCreateRequest request)
    {
        if (request.SchemaVersion != 1
            || request.Parameters.ValueKind != JsonValueKind.Object
            || request.Parameters.GetRawText().Length > MaximumParametersBytes
            || request.TtlMinutes is < 5 or > 1440
            || request.AuditReason is not { Length: >= 1 and <= 256 }
            || !IdempotencyKeyValidator.IsValid(request.IdempotencyKey))
        {
            return false;
        }
        if (request.ActionType == "preflight")
        {
            return !request.Parameters.EnumerateObject().Any();
        }
        if (request.ActionType != "system.base-install")
        {
            return false;
        }
        return SystemBaseInstallSchema.TryParse(request.Parameters, out _);
    }

    public static bool IsValid(ProvisioningJobCommandRequest request)
        => request.Reason.Length is >= 1 and <= 256
           && IdempotencyKeyValidator.IsValid(request.IdempotencyKey);

    public static bool IsValid(ProvisioningJobProgressRequest request)
        => request.State is ProvisioningJobStates.Preflight
            or ProvisioningJobStates.Running
            or ProvisioningJobStates.Verifying
            or ProvisioningJobStates.Completed
            or ProvisioningJobStates.Failed
            or ProvisioningJobStates.NeedsReconciliation
            or ProvisioningJobStates.RollingBack
            or ProvisioningJobStates.RolledBack
            or ProvisioningJobStates.RollbackFailed
           && request.ProgressPercent is >= 0 and <= 100
           && IsSafeCode(request.Step, 64)
           && IsSafeCode(request.EventCode, 64)
           && request.Message.Length <= 512
           && IdempotencyKeyValidator.IsValid(request.IdempotencyKey);

    public static bool IsValid(ProvisioningPreflightReportRequest request)
        => request.ObservedAt >= DateTimeOffset.UtcNow.AddHours(-1)
           && request.ObservedAt <= DateTimeOffset.UtcNow.AddMinutes(1)
           && request.Facts is not null
           && IsSafeFact(request.Facts.OperatingSystem, 32)
           && IsSafeFact(request.Facts.OperatingSystemVersion, 64)
           && request.Facts.Architecture is "x64" or "x86" or "arm" or "arm64"
           && IdempotencyKeyValidator.IsValid(request.IdempotencyKey);

    public static bool IsValid(SystemBaseInstallPlanReportRequest request)
        => request.Plan is not null
           && request.Plan.Packages is { Length: <= 64 }
           && request.Plan.Warnings is { Length: <= 2 }
           && IdempotencyKeyValidator.IsValid(request.IdempotencyKey);

    public static bool IsValid(ProvisioningExecutionGrantRequest request)
        => IdempotencyKeyValidator.IsValid(request.IdempotencyKey);

    public static bool IsValidId(string id)
        => id.Length == 32 && Guid.TryParseExact(id, "N", out _);

    public static bool RequiresConfirmation(string actionType)
        => actionType == "system.base-install";

    private static bool IsSafeCode(string value, int maximumLength)
        => value.Length is >= 1 && value.Length <= maximumLength
           && value.All(character => character is >= 'a' and <= 'z'
               or >= '0' and <= '9'
               or '.' or '-' or '_');

    private static bool IsSafeFact(string? value, int maximumLength)
        => value is not null
           && value.Length is >= 1 && value.Length <= maximumLength
           && value.All(character => char.IsAsciiLetterOrDigit(character)
               || character is '_' or '-' or '.');

}

internal static class PreflightDesiredStateValidator
{
    private static readonly HashSet<string> SupportedArchitectures =
        new(["x64", "x86", "arm", "arm64"], StringComparer.Ordinal);

    public static bool IsValid(PreflightDesiredStateUpdateRequest request)
        => request.SchemaVersion == 1
           && request.Desired is not null
           && request.Desired.AllowedArchitectures is { Length: >= 1 and <= 4 }
           && request.Desired.AllowedArchitectures.Distinct(StringComparer.Ordinal).Count()
               == request.Desired.AllowedArchitectures.Length
           && request.Desired.AllowedArchitectures.All(SupportedArchitectures.Contains)
           && request.AuditReason is { Length: >= 1 and <= 256 }
           && IdempotencyKeyValidator.IsValid(request.IdempotencyKey);
}
