//! Analytics API routes
//!
//! Provides read-only access to TimescaleDB continuous aggregates for dashboard
//! widgets and time-series analytics. All data is pre-computed by TimescaleDB
//! continuous aggregate policies — these endpoints simply query the materialized views.

use axum::{
    extract::{Query, State},
    http::StatusCode,
    response::IntoResponse,
    routing::get,
    Json, Router,
};
use std::sync::Arc;

use attune_common::repositories::analytics::AnalyticsRepository;

use crate::{
    auth::middleware::RequireAuth,
    dto::{
        analytics::{
            AnalyticsQueryParams, DashboardAnalyticsResponse, EnforcementVolumeResponse,
            EventVolumeResponse, ExecutionStatusTimeSeriesResponse, ExecutionThroughputResponse,
            FailureRateResponse, TimeSeriesPoint, WorkerStatusTimeSeriesResponse,
        },
        common::ApiResponse,
    },
    middleware::ApiResult,
    state::AppState,
};

/// Get a combined dashboard analytics payload.
///
/// Returns all key metrics in a single response to avoid multiple round-trips
/// from the dashboard page. Includes execution throughput, status transitions,
/// event volume, enforcement volume, worker status, and failure rate.
#[utoipa::path(
    get,
    path = "/api/v1/analytics/dashboard",
    tag = "analytics",
    params(AnalyticsQueryParams),
    responses(
        (status = 200, description = "Dashboard analytics", body = inline(ApiResponse<DashboardAnalyticsResponse>)),
    ),
    security(("bearer_auth" = []))
)]
pub async fn get_dashboard_analytics(
    State(state): State<Arc<AppState>>,
    RequireAuth(_user): RequireAuth,
    Query(query): Query<AnalyticsQueryParams>,
) -> ApiResult<impl IntoResponse> {
    let range = query.to_time_range();

    // Run all aggregate queries concurrently
    let (throughput, status, events, enforcements, workers, failure_rate) = tokio::try_join!(
        AnalyticsRepository::execution_throughput_hourly(&state.db, &range),
        AnalyticsRepository::execution_status_hourly(&state.db, &range),
        AnalyticsRepository::event_volume_hourly(&state.db, &range),
        AnalyticsRepository::enforcement_volume_hourly(&state.db, &range),
        AnalyticsRepository::worker_status_hourly(&state.db, &range),
        AnalyticsRepository::execution_failure_rate(&state.db, &range),
    )?;

    let response = DashboardAnalyticsResponse {
        since: range.since,
        until: range.until,
        execution_throughput: throughput.into_iter().map(Into::into).collect(),
        execution_status: status.into_iter().map(Into::into).collect(),
        event_volume: events.into_iter().map(Into::into).collect(),
        enforcement_volume: enforcements.into_iter().map(Into::into).collect(),
        worker_status: workers.into_iter().map(Into::into).collect(),
        failure_rate: FailureRateResponse::from_summary(failure_rate, &range),
    };

    Ok((StatusCode::OK, Json(ApiResponse::new(response))))
}

/// Get execution status transitions over time.
///
/// Returns hourly buckets of execution status transitions (e.g., how many
/// executions moved to "completed", "failed", "running" per hour).
#[utoipa::path(
    get,
    path = "/api/v1/analytics/executions/status",
    tag = "analytics",
    params(AnalyticsQueryParams),
    responses(
        (status = 200, description = "Execution status transitions", body = inline(ApiResponse<ExecutionStatusTimeSeriesResponse>)),
    ),
    security(("bearer_auth" = []))
)]
pub async fn get_execution_status_analytics(
    State(state): State<Arc<AppState>>,
    RequireAuth(_user): RequireAuth,
    Query(query): Query<AnalyticsQueryParams>,
) -> ApiResult<impl IntoResponse> {
    let range = query.to_time_range();
    let rows = AnalyticsRepository::execution_status_hourly(&state.db, &range).await?;

    let data: Vec<TimeSeriesPoint> = rows.into_iter().map(Into::into).collect();

    let response = ExecutionStatusTimeSeriesResponse {
        since: range.since,
        until: range.until,
        data,
    };

    Ok((StatusCode::OK, Json(ApiResponse::new(response))))
}

/// Get execution throughput over time.
///
/// Returns hourly buckets of execution creation counts.
#[utoipa::path(
    get,
    path = "/api/v1/analytics/executions/throughput",
    tag = "analytics",
    params(AnalyticsQueryParams),
    responses(
        (status = 200, description = "Execution throughput", body = inline(ApiResponse<ExecutionThroughputResponse>)),
    ),
    security(("bearer_auth" = []))
)]
pub async fn get_execution_throughput_analytics(
    State(state): State<Arc<AppState>>,
    RequireAuth(_user): RequireAuth,
    Query(query): Query<AnalyticsQueryParams>,
) -> ApiResult<impl IntoResponse> {
    let range = query.to_time_range();
    let rows = AnalyticsRepository::execution_throughput_hourly(&state.db, &range).await?;

    let data: Vec<TimeSeriesPoint> = rows.into_iter().map(Into::into).collect();

    let response = ExecutionThroughputResponse {
        since: range.since,
        until: range.until,
        data,
    };

    Ok((StatusCode::OK, Json(ApiResponse::new(response))))
}

/// Get the execution failure rate summary.
///
/// Returns aggregate failure/timeout/completion counts and the failure rate
/// percentage over the requested time range.
#[utoipa::path(
    get,
    path = "/api/v1/analytics/executions/failure-rate",
    tag = "analytics",
    params(AnalyticsQueryParams),
    responses(
        (status = 200, description = "Failure rate summary", body = inline(ApiResponse<FailureRateResponse>)),
    ),
    security(("bearer_auth" = []))
)]
pub async fn get_failure_rate_analytics(
    State(state): State<Arc<AppState>>,
    RequireAuth(_user): RequireAuth,
    Query(query): Query<AnalyticsQueryParams>,
) -> ApiResult<impl IntoResponse> {
    let range = query.to_time_range();
    let summary = AnalyticsRepository::execution_failure_rate(&state.db, &range).await?;

    let response = FailureRateResponse::from_summary(summary, &range);

    Ok((StatusCode::OK, Json(ApiResponse::new(response))))
}

/// Get event volume over time.
///
/// Returns hourly buckets of event creation counts, aggregated across all triggers.
#[utoipa::path(
    get,
    path = "/api/v1/analytics/events/volume",
    tag = "analytics",
    params(AnalyticsQueryParams),
    responses(
        (status = 200, description = "Event volume", body = inline(ApiResponse<EventVolumeResponse>)),
    ),
    security(("bearer_auth" = []))
)]
pub async fn get_event_volume_analytics(
    State(state): State<Arc<AppState>>,
    RequireAuth(_user): RequireAuth,
    Query(query): Query<AnalyticsQueryParams>,
) -> ApiResult<impl IntoResponse> {
    let range = query.to_time_range();
    let rows = AnalyticsRepository::event_volume_hourly(&state.db, &range).await?;

    let data: Vec<TimeSeriesPoint> = rows.into_iter().map(Into::into).collect();

    let response = EventVolumeResponse {
        since: range.since,
        until: range.until,
        data,
    };

    Ok((StatusCode::OK, Json(ApiResponse::new(response))))
}

/// Get worker status transitions over time.
///
/// Returns hourly buckets of worker status changes (online/offline/draining).
#[utoipa::path(
    get,
    path = "/api/v1/analytics/workers/status",
    tag = "analytics",
    params(AnalyticsQueryParams),
    responses(
        (status = 200, description = "Worker status transitions", body = inline(ApiResponse<WorkerStatusTimeSeriesResponse>)),
    ),
    security(("bearer_auth" = []))
)]
pub async fn get_worker_status_analytics(
    State(state): State<Arc<AppState>>,
    RequireAuth(_user): RequireAuth,
    Query(query): Query<AnalyticsQueryParams>,
) -> ApiResult<impl IntoResponse> {
    let range = query.to_time_range();
    let rows = AnalyticsRepository::worker_status_hourly(&state.db, &range).await?;

    let data: Vec<TimeSeriesPoint> = rows.into_iter().map(Into::into).collect();

    let response = WorkerStatusTimeSeriesResponse {
        since: range.since,
        until: range.until,
        data,
    };

    Ok((StatusCode::OK, Json(ApiResponse::new(response))))
}

/// Get enforcement volume over time.
///
/// Returns hourly buckets of enforcement creation counts, aggregated across all rules.
#[utoipa::path(
    get,
    path = "/api/v1/analytics/enforcements/volume",
    tag = "analytics",
    params(AnalyticsQueryParams),
    responses(
        (status = 200, description = "Enforcement volume", body = inline(ApiResponse<EnforcementVolumeResponse>)),
    ),
    security(("bearer_auth" = []))
)]
pub async fn get_enforcement_volume_analytics(
    State(state): State<Arc<AppState>>,
    RequireAuth(_user): RequireAuth,
    Query(query): Query<AnalyticsQueryParams>,
) -> ApiResult<impl IntoResponse> {
    let range = query.to_time_range();
    let rows = AnalyticsRepository::enforcement_volume_hourly(&state.db, &range).await?;

    let data: Vec<TimeSeriesPoint> = rows.into_iter().map(Into::into).collect();

    let response = EnforcementVolumeResponse {
        since: range.since,
        until: range.until,
        data,
    };

    Ok((StatusCode::OK, Json(ApiResponse::new(response))))
}

// ---------------------------------------------------------------------------
// Router
// ---------------------------------------------------------------------------

/// Build the analytics routes.
///
/// Mounts:
/// - `GET /analytics/dashboard`              — combined dashboard payload
/// - `GET /analytics/executions/status`      — execution status transitions
/// - `GET /analytics/executions/throughput`   — execution creation throughput
/// - `GET /analytics/executions/failure-rate` — failure rate summary
/// - `GET /analytics/events/volume`          — event creation volume
/// - `GET /analytics/workers/status`         — worker status transitions
/// - `GET /analytics/enforcements/volume`    — enforcement creation volume
pub fn routes() -> Router<Arc<AppState>> {
    Router::new()
        .route("/analytics/dashboard", get(get_dashboard_analytics))
        .route(
            "/analytics/executions/status",
            get(get_execution_status_analytics),
        )
        .route(
            "/analytics/executions/throughput",
            get(get_execution_throughput_analytics),
        )
        .route(
            "/analytics/executions/failure-rate",
            get(get_failure_rate_analytics),
        )
        .route("/analytics/events/volume", get(get_event_volume_analytics))
        .route(
            "/analytics/workers/status",
            get(get_worker_status_analytics),
        )
        .route(
            "/analytics/enforcements/volume",
            get(get_enforcement_volume_analytics),
        )
}
