//! Health check and status endpoints for API servers

use axum::Json;
use serde_json::json;
use std::sync::OnceLock;
use std::time::SystemTime;

/// Server uptime tracker (initialized at startup)
static SERVER_START_TIME: OnceLock<SystemTime> = OnceLock::new();

/// Initialize server uptime tracking
///
/// This should be called once at application startup to initialize the uptime timer.
pub fn init_uptime() {
    let _ = SERVER_START_TIME.set(SystemTime::now());
}

/// Get server uptime in seconds
pub fn get_uptime() -> u64 {
    SERVER_START_TIME
        .get()
        .and_then(|start| start.elapsed().ok())
        .map(|duration| duration.as_secs())
        .unwrap_or(0)
}

/// Format uptime into a human-readable string (e.g., "1d 5h", "3h 42m", "45m 30s")
pub fn format_uptime(uptime_seconds: u64) -> String {
    let uptime_minutes = uptime_seconds / 60;
    let uptime_hours = uptime_minutes / 60;
    let uptime_days = uptime_hours / 24;

    if uptime_days > 0 {
        format!("{}d {}h", uptime_days, uptime_hours % 24)
    } else if uptime_hours > 0 {
        format!("{}h {}m", uptime_hours, uptime_minutes % 60)
    } else {
        format!("{}m {}s", uptime_minutes, uptime_seconds % 60)
    }
}

/// Basic health check response without database connection check
pub async fn health_check() -> Json<serde_json::Value> {
    let uptime = get_uptime();

    Json(json!({
        "status": "healthy",
        "uptime": {
            "seconds": uptime,
            "formatted": format_uptime(uptime)
        },
        "timestamp": chrono::Utc::now().to_rfc3339()
    }))
}

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

    #[test]
    fn test_uptime_seconds_only() {
        let formatted = format_uptime(5);
        assert!(formatted.contains("m") || formatted.contains("s"));
    }

    #[test]
    fn test_uptime_minutes_and_seconds() {
        let formatted = format_uptime(125); // 2 minutes 5 seconds
        assert!(formatted.contains("m"));
    }

    #[test]
    fn test_uptime_hours_format() {
        let formatted = format_uptime(3661); // 1 hour, 1 minute, 1 second
        assert!(formatted.contains("h"));
    }

    #[test]
    fn test_uptime_days_format() {
        let formatted = format_uptime(86461); // 1 day, 1 minute, 1 second
        assert!(formatted.contains("d"));
    }

    #[test]
    fn test_uptime_zero() {
        let formatted = format_uptime(0);
        assert_eq!(formatted, "0m 0s");
    }

    #[test]
    fn test_server_start_time_initialization() {
        // Initialize uptime tracking
        init_uptime();
        // Verify we can get uptime (u64 is always >= 0, so just verify it works)
        let _uptime = get_uptime();
        // If we got here without panicking, initialization worked
    }

    #[test]
    fn test_uptime_increases() {
        init_uptime();
        let uptime1 = get_uptime();
        std::thread::sleep(std::time::Duration::from_millis(10));
        let uptime2 = get_uptime();
        // uptime2 should be >= uptime1
        assert!(uptime2 >= uptime1);
    }
}
