use axum::{extract::State, Json};
use chrono::Utc;
use serde::Serialize;
use crate::{error::ApiResult, AppState};
#[derive(Debug, Serialize)]
pub struct StatusResponse {
pub status: String, pub timestamp: String,
pub services: Vec<ServiceStatus>,
pub incidents: Vec<Incident>,
}
#[derive(Debug, Serialize)]
pub struct ServiceStatus {
pub name: String,
pub status: String, pub message: Option<String>,
}
#[derive(Debug, Serialize)]
pub struct Incident {
pub id: String,
pub title: String,
pub status: String, pub started_at: String,
pub resolved_at: Option<String>,
pub impact: String, }
pub async fn get_status(State(state): State<AppState>) -> ApiResult<Json<StatusResponse>> {
let mut services = Vec::new();
let db_status = match state.store.health_check().await {
Ok(_) => ("operational", None),
Err(_) => ("down", Some("Database connection failed".to_string())),
};
services.push(ServiceStatus {
name: "Database".to_string(),
status: db_status.0.to_string(),
message: db_status.1,
});
if let Some(redis) = &state.redis {
let redis_status = match redis.ping().await {
Ok(_) => ("operational", None),
Err(_) => ("degraded", Some("Redis connection failed".to_string())),
};
services.push(ServiceStatus {
name: "Redis".to_string(),
status: redis_status.0.to_string(),
message: redis_status.1,
});
} else {
services.push(ServiceStatus {
name: "Redis".to_string(),
status: "operational".to_string(),
message: Some("Not configured".to_string()),
});
}
let storage_status = match state.storage.health_check().await {
Ok(_) => ("operational", None),
Err(_) => ("degraded", Some("Storage connection failed".to_string())),
};
services.push(ServiceStatus {
name: "Storage".to_string(),
status: storage_status.0.to_string(),
message: storage_status.1,
});
services.push(ServiceStatus {
name: "API".to_string(),
status: "operational".to_string(),
message: None,
});
let overall_status = if services.iter().any(|s| s.status == "down") {
"down"
} else if services.iter().any(|s| s.status == "degraded") {
"degraded"
} else {
"operational"
};
let incidents: Vec<Incident> = services
.iter()
.filter(|s| s.status != "operational")
.enumerate()
.map(|(i, service)| {
let impact = if service.status == "down" {
"critical"
} else {
"minor"
};
Incident {
id: format!("auto-{}", i + 1),
title: format!("{} service {}", service.name, service.status),
status: "investigating".to_string(),
started_at: Utc::now().to_rfc3339(),
resolved_at: None,
impact: impact.to_string(),
}
})
.collect();
Ok(Json(StatusResponse {
status: overall_status.to_string(),
timestamp: Utc::now().to_rfc3339(),
services,
incidents,
}))
}