using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.Extensions.Diagnostics.HealthChecks;

namespace DodoSSH.Api.Setup;

/// <summary>
/// Health check wiring.
/// </summary>
/// <remarks>
/// The split between liveness and readiness is deliberate and load-bearing for the
/// relay: <c>/healthz/live</c> checks the process and nothing else, so a transient
/// PostgreSQL outage cannot cause the orchestrator to restart the container and
/// guillotine every live SSH session. Dependency checks belong in
/// <c>/healthz/ready</c>, which only removes the instance from load balancing.
/// </remarks>
internal static class HealthChecks
{
    /// <summary>Tag for checks that gate readiness (dependencies).</summary>
    internal const string ReadyTag = "ready";

    /// <summary>Tag for checks that gate startup completion.</summary>
    internal const string StartupTag = "startup";

    internal static IServiceCollection AddDodoHealthChecks(this IServiceCollection services)
    {
        services.AddHealthChecks();

        // Dependency checks are registered by the milestone that introduces the
        // dependency, each tagged ReadyTag:
        //   M1 — PostgreSQL, OIDC discovery + JWKS reachability, pending migrations
        //   M4 — Data Protection key ring readability
        return services;
    }

    internal static WebApplication MapDodoHealthChecks(this WebApplication app)
    {
        // Liveness: process is running and the pipeline responds. No dependencies.
        app.MapHealthChecks("/healthz/live", new HealthCheckOptions
        {
            Predicate = _ => false,
        }).AllowAnonymous();

        // Readiness: safe to route traffic here.
        app.MapHealthChecks("/healthz/ready", new HealthCheckOptions
        {
            Predicate = registration => registration.Tags.Contains(ReadyTag),
        }).AllowAnonymous();

        // Startup: one-time initialisation finished (K8s startupProbe).
        app.MapHealthChecks("/healthz/startup", new HealthCheckOptions
        {
            Predicate = registration => registration.Tags.Contains(StartupTag),
        }).AllowAnonymous();

        return app;
    }
}
