use axum::{Json, extract::State, http::StatusCode, response::IntoResponse};
use common_contracts::registry::{Heartbeat, ServiceRegistration};
use tracing::{info, warn};

use crate::{
    error::Result,
    state::AppState,
};

/// [POST /v1/registry/register]
pub async fn register_service(
    State(state): State<AppState>,
    Json(payload): Json<ServiceRegistration>,
) -> Result<impl IntoResponse> {
    info!(
        "Registering service: {} ({}) at {}",
        payload.service_id, payload.service_name, payload.base_url
    );

    state.registry.register(payload);

    Ok(StatusCode::OK)
}

/// [POST /v1/registry/heartbeat]
pub async fn heartbeat(
    State(state): State<AppState>,
    Json(payload): Json<Heartbeat>,
) -> Result<impl IntoResponse> {
    if state.registry.update_heartbeat(&payload.service_id) {
        Ok(StatusCode::OK)
    } else {
        // This is the key part for self-healing: tell the provider we don't know them
        warn!(
            "Received heartbeat from unknown service: {}",
            payload.service_id
        );
        Ok(StatusCode::NOT_FOUND)
    }
}

/// [POST /v1/registry/deregister]
pub async fn deregister_service(
    State(state): State<AppState>,
    Json(payload): Json<serde_json::Value>,
) -> Result<impl IntoResponse> {
    let service_id = payload
        .get("service_id")
        .and_then(|v| v.as_str())
        .ok_or_else(|| crate::error::AppError::BadRequest("Missing service_id".into()))?;

    info!("Deregistering service: {}", service_id);

    state.registry.deregister(service_id);

    Ok(StatusCode::OK)
}
