use axum::{extract::State, Json}; use super::{AppError, AppState}; pub async fn get_stats( State(state): State, ) -> Result, AppError> { // Total sessions let total_sessions: i64 = sqlx::query_scalar("SELECT COUNT(*) FROM imaging_log") .fetch_one(&state.pool) .await?; // Total integration time let total_integration_min: Option = sqlx::query_scalar("SELECT SUM(integration_min) FROM imaging_log") .fetch_optional(&state.pool) .await? .flatten(); // Objects imaged (at least one keeper) let objects_with_keeper: i64 = sqlx::query_scalar( "SELECT COUNT(DISTINCT catalog_id) FROM imaging_log WHERE quality = 'keeper'", ) .fetch_one(&state.pool) .await?; // Filter usage let filter_usage = sqlx::query( "SELECT filter_id, COUNT(*) as count, SUM(integration_min) as total_min FROM imaging_log GROUP BY filter_id", ) .fetch_all(&state.pool) .await?; let filter_stats: Vec = filter_usage.iter().map(|r| { use sqlx::Row; serde_json::json!({ "filter_id": r.try_get::("filter_id").unwrap_or_default(), "count": r.try_get::("count").unwrap_or_default(), "total_min": r.try_get::, _>("total_min").unwrap_or_default(), }) }).collect(); // Integration per month (last 12 months) let monthly = sqlx::query( r#"SELECT substr(session_date, 1, 7) as month, COUNT(*) as sessions, SUM(integration_min) as total_min FROM imaging_log WHERE session_date >= date('now', '-12 months') GROUP BY month ORDER BY month"#, ) .fetch_all(&state.pool) .await?; let monthly_stats: Vec = monthly.iter().map(|r| { use sqlx::Row; serde_json::json!({ "month": r.try_get::("month").unwrap_or_default(), "sessions": r.try_get::("sessions").unwrap_or_default(), "total_min": r.try_get::, _>("total_min").unwrap_or_default(), }) }).collect(); // Object type breakdown let type_breakdown = sqlx::query( r#"SELECT c.obj_type, COUNT(*) as sessions, SUM(l.integration_min) as total_min FROM imaging_log l JOIN catalog c ON c.id = l.catalog_id GROUP BY c.obj_type ORDER BY total_min DESC"#, ) .fetch_all(&state.pool) .await?; let type_stats: Vec = type_breakdown.iter().map(|r| { use sqlx::Row; serde_json::json!({ "obj_type": r.try_get::("obj_type").unwrap_or_default(), "sessions": r.try_get::("sessions").unwrap_or_default(), "total_min": r.try_get::, _>("total_min").unwrap_or_default(), }) }).collect(); // Quality breakdown let quality = sqlx::query( "SELECT quality, COUNT(*) as count FROM imaging_log GROUP BY quality", ) .fetch_all(&state.pool) .await?; let quality_stats: Vec = quality.iter().map(|r| { use sqlx::Row; serde_json::json!({ "quality": r.try_get::("quality").unwrap_or_default(), "count": r.try_get::("count").unwrap_or_default(), }) }).collect(); // Top targets by integration let top_targets = sqlx::query( r#"SELECT c.id, c.name, c.common_name, c.obj_type, COUNT(l.id) as sessions, SUM(l.integration_min) as total_min FROM imaging_log l JOIN catalog c ON c.id = l.catalog_id GROUP BY l.catalog_id ORDER BY total_min DESC LIMIT 20"#, ) .fetch_all(&state.pool) .await?; let top_target_list: Vec = top_targets.iter().map(|r| { use sqlx::Row; serde_json::json!({ "id": r.try_get::("id").unwrap_or_default(), "name": r.try_get::("name").unwrap_or_default(), "common_name": r.try_get::, _>("common_name").unwrap_or_default(), "obj_type": r.try_get::("obj_type").unwrap_or_default(), "sessions": r.try_get::("sessions").unwrap_or_default(), "total_min": r.try_get::, _>("total_min").unwrap_or_default(), }) }).collect(); // Guiding RMS over time let guiding = sqlx::query( "SELECT session_date, rms_total, rms_ra, rms_dec FROM phd2_logs ORDER BY session_date", ) .fetch_all(&state.pool) .await?; let guiding_data: Vec = guiding.iter().map(|r| { use sqlx::Row; serde_json::json!({ "date": r.try_get::("session_date").unwrap_or_default(), "rms_total": r.try_get::, _>("rms_total").unwrap_or_default(), "rms_ra": r.try_get::, _>("rms_ra").unwrap_or_default(), "rms_dec": r.try_get::, _>("rms_dec").unwrap_or_default(), }) }).collect(); Ok(Json(serde_json::json!({ "total_sessions": total_sessions, "total_integration_min": total_integration_min.unwrap_or(0), "objects_with_keeper": objects_with_keeper, "filter_usage": filter_stats, "monthly": monthly_stats, "by_type": type_stats, "quality": quality_stats, "top_targets": top_target_list, "guiding": guiding_data, }))) }