//! HTTP handlers for escalation event management.

use crate::{
    dto::{ErrorResponse, EscalationEventDto, EscalationListResponse},
    AppState,
};
use axum::{
    extract::{Path, Query, State},
    http::StatusCode,
    Json,
};
use serde::Deserialize;
use stemedb_storage::EscalationStore;
use tracing::instrument;

/// Query parameters for listing escalations.
#[derive(Debug, Deserialize)]
pub struct EscalationQueryParams {
    /// Only return escalations since this timestamp (nanoseconds).
    pub since: Option<u64>,
}

/// GET /v1/admin/escalations
///
/// List all pending escalation events, or all escalations since a timestamp.
#[utoipa::path(
    get,
    path = "/v1/admin/escalations",
    params(
        ("since" = Option<u64>, Query, description = "Only return escalations since this timestamp (nanoseconds)")
    ),
    responses(
        (status = 200, description = "Escalations retrieved successfully", body = EscalationListResponse),
        (status = 500, description = "Internal server error", body = ErrorResponse)
    ),
    tag = "admin"
)]
#[instrument(skip(state))]
pub async fn list_escalations(
    State(state): State<AppState>,
    Query(params): Query<EscalationQueryParams>,
) -> std::result::Result<Json<EscalationListResponse>, (StatusCode, Json<ErrorResponse>)> {
    let store = &state.escalation_store;
    let events = match params.since {
        Some(since) => store.get_escalations_since(since).await.map_err(|e| {
            tracing::error!(error = %e, "Failed to get escalations since timestamp");
            (
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(ErrorResponse {
                    error: "Failed to retrieve escalations".to_string(),
                    code: "ESCALATION_RETRIEVAL_ERROR".to_string(),
                }),
            )
        })?,
        None => store.get_pending_escalations().await.map_err(|e| {
            tracing::error!(error = %e, "Failed to get pending escalations");
            (
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(ErrorResponse {
                    error: "Failed to retrieve pending escalations".to_string(),
                    code: "ESCALATION_RETRIEVAL_ERROR".to_string(),
                }),
            )
        })?,
    };

    let dtos: Vec<EscalationEventDto> = events.iter().map(EscalationEventDto::from).collect();

    Ok(Json(EscalationListResponse { escalations: dtos, count: events.len() }))
}

/// POST /v1/admin/escalations/{id}/resolve
///
/// Mark an escalation event as resolved.
#[utoipa::path(
    post,
    path = "/v1/admin/escalations/{id}/resolve",
    params(
        ("id" = String, Path, description = "Hex-encoded escalation event ID")
    ),
    responses(
        (status = 200, description = "Escalation resolved successfully"),
        (status = 404, description = "Escalation not found", body = ErrorResponse),
        (status = 400, description = "Invalid escalation ID", body = ErrorResponse),
        (status = 500, description = "Internal server error", body = ErrorResponse)
    ),
    tag = "admin"
)]
#[instrument(skip(state))]
pub async fn resolve_escalation(
    State(state): State<AppState>,
    Path(id_hex): Path<String>,
) -> std::result::Result<StatusCode, (StatusCode, Json<ErrorResponse>)> {
    let store = &state.escalation_store;
    // Decode the hex ID
    let id_bytes = hex::decode(&id_hex).map_err(|_| {
        (
            StatusCode::BAD_REQUEST,
            Json(ErrorResponse {
                error: "Invalid escalation ID format".to_string(),
                code: "INVALID_ESCALATION_ID".to_string(),
            }),
        )
    })?;

    if id_bytes.len() != 32 {
        return Err((
            StatusCode::BAD_REQUEST,
            Json(ErrorResponse {
                error: "Escalation ID must be 32 bytes".to_string(),
                code: "INVALID_ESCALATION_ID".to_string(),
            }),
        ));
    }

    let mut id = [0u8; 32];
    id.copy_from_slice(&id_bytes);

    let resolved = store.resolve_escalation(&id).await.map_err(|e| {
        tracing::error!(error = %e, id = %id_hex, "Failed to resolve escalation");
        (
            StatusCode::INTERNAL_SERVER_ERROR,
            Json(ErrorResponse {
                error: "Failed to resolve escalation".to_string(),
                code: "ESCALATION_RESOLVE_ERROR".to_string(),
            }),
        )
    })?;

    if resolved {
        Ok(StatusCode::OK)
    } else {
        Err((
            StatusCode::NOT_FOUND,
            Json(ErrorResponse {
                error: "Escalation not found".to_string(),
                code: "ESCALATION_NOT_FOUND".to_string(),
            }),
        ))
    }
}
