use axum::{
    extract::{Path, State},
    http::StatusCode,
    response::Json,
};
use serde::Deserialize;
use tracing::error;
use uuid::Uuid;

use super::{
    accumulate_metrics, p95_from_metrics,
    types::{SpawnRequest, SpawnResponse},
};
use crate::{ApiResponse, SharedState};

pub async fn spawn_runner(
    State(state): State<SharedState>,
    Json(req): Json<SpawnRequest>,
) -> Result<Json<ApiResponse<SpawnResponse>>, StatusCode> {
    let pool = state.vm_pool.as_ref().ok_or_else(|| {
        error!("vm_pool not configured — RUNNER_SCRIPT may be missing");
        StatusCode::SERVICE_UNAVAILABLE
    })?;

    match pool.spawn_runner(req).await {
        Ok(resp) => Ok(Json(ApiResponse::success(resp))),
        Err(e) => {
            error!(error = %e, "vm_pool spawn_runner failed");
            Err(StatusCode::INTERNAL_SERVER_ERROR)
        }
    }
}

pub async fn destroy_runner(
    State(state): State<SharedState>,
    Path(lease_id): Path<String>,
) -> Result<Json<ApiResponse<()>>, StatusCode> {
    let pool = state.vm_pool.as_ref().ok_or(StatusCode::SERVICE_UNAVAILABLE)?;

    let uuid = Uuid::parse_str(&lease_id).map_err(|_| StatusCode::BAD_REQUEST)?;

    match pool.destroy_runner(uuid).await {
        Ok(()) => Ok(Json(ApiResponse::success(()))),
        Err(e) => {
            error!(lease_id = %lease_id, error = %e, "vm_pool destroy_runner failed");
            Err(StatusCode::INTERNAL_SERVER_ERROR)
        }
    }
}

pub async fn get_p95(
    State(state): State<SharedState>,
    Path(workspace): Path<String>,
) -> Result<Json<ApiResponse<crate::vm_pool::types::P95Stats>>, StatusCode> {
    match p95_from_metrics(&state.build_metrics, &workspace) {
        Some(stats) => Ok(Json(ApiResponse::success(stats))),
        None => Err(StatusCode::NOT_FOUND),
    }
}

#[derive(Deserialize)]
pub struct BuildMetricsPayload {
    pub workspace: String,
    pub cpu_secs: f64,
    pub mem_peak_mb: f64,
    pub duration_secs: f64,
}

pub async fn record_build_metrics(
    State(state): State<SharedState>,
    Json(payload): Json<BuildMetricsPayload>,
) -> Json<ApiResponse<()>> {
    accumulate_metrics(
        &state.build_metrics,
        &payload.workspace,
        payload.cpu_secs,
        payload.mem_peak_mb,
        payload.duration_secs,
    );
    Json(ApiResponse::success(()))
}
