//! Shared health-probe handlers for the standalone and cluster routers.
//!
//! The standalone router ([`crate::router`]) and the cluster router
//! ([`crate::cluster`]) both expose the same Kubernetes-style probe endpoints
//! `GET /health/startup` and `GET /health/live`. Their handlers and the JSON
//! body they return were previously byte-identical copies in each module; any
//! drift between the two (e.g. a renamed field on one side) would silently
//! change one mode's probe contract. This module is the single source of truth
//! so the two routers cannot diverge, mirroring the [`crate::dto`] anti-drift
//! pattern for the data surface.

use axum::Json;

/// Shared probe body: `{"ok": true, "service": "tidaldb"}`.
///
/// Both `/health/startup` and `/health/live` return this fixed body — they are
/// unconditional 200s (the process is up and there are no migrations to gate
/// readiness on). The richer mode-specific readiness check (`GET /health`)
/// stays in each router because it inspects mode-specific state.
fn probe_body() -> serde_json::Value {
    serde_json::json!({ "ok": true, "service": "tidaldb" })
}

/// Startup probe: always 200 (no migrations to check).
pub async fn health_startup() -> Json<serde_json::Value> {
    Json(probe_body())
}

/// Liveness probe: always 200 (process is alive).
pub async fn health_live() -> Json<serde_json::Value> {
    Json(probe_body())
}

#[cfg(test)]
mod tests {
    use super::*;

    /// Both probes return the same fixed body, so the standalone and cluster
    /// routers cannot advertise a different probe contract.
    #[tokio::test]
    async fn probes_return_shared_body() {
        let expected = serde_json::json!({ "ok": true, "service": "tidaldb" });
        assert_eq!(health_startup().await.0, expected);
        assert_eq!(health_live().await.0, expected);
        assert_eq!(probe_body(), expected);
    }
}
