//! Admin API handlers (ranges, force sync, metrics).

use axum::extract::State;
use axum::response::IntoResponse;
use axum::Json;
use metrics_exporter_prometheus::PrometheusHandle;
use std::sync::Arc;
use tracing::{info, instrument};

use crate::gateway::service::GatewayState;

use super::types::{ApiError, ForceSyncRequest, ForceSyncResponse, RangeInfoDto, RangesResponse};

/// GET /v1/admin/ranges - List all shard/range assignments.
///
/// Returns information about all shards in the cluster, including their key ranges,
/// replica assignments, and size metrics. Useful for operators to understand
/// data distribution and identify hot spots.
#[instrument(skip(state))]
pub async fn handle_ranges(State(state): State<Arc<GatewayState>>) -> Json<RangesResponse> {
    let meta = state.router.get_meta_range();

    let ranges: Vec<RangeInfoDto> = meta
        .descriptors
        .values()
        .map(|d| RangeInfoDto {
            range_id: format!("shard_{}", d.shard_id),
            start_key: d.start_key.as_ref().map(hex::encode).unwrap_or_default(),
            end_key: d.end_key.as_ref().map(hex::encode).unwrap_or_default(),
            size_bytes: d.size_bytes,
            assertion_count: d.assertion_count,
            leader_node: d.replicas.first().map(|n| n.short_hex()),
            replica_nodes: d.replicas.iter().map(|n| n.short_hex()).collect(),
            generation: d.generation,
        })
        .collect();

    let total_ranges = ranges.len();
    Json(RangesResponse { ranges, total_ranges })
}

/// POST /v1/admin/sync - Force an anti-entropy sync cycle.
///
/// Triggers immediate sync with peers, bypassing the normal interval timer.
/// Useful for operators who need to force convergence after network partitions
/// or during incident recovery.
#[instrument(skip(state))]
pub async fn handle_force_sync(
    State(state): State<Arc<GatewayState>>,
    Json(_req): Json<ForceSyncRequest>,
) -> Result<Json<ForceSyncResponse>, ApiError> {
    // Notify all registered anti-entropy workers
    let notifiers = state.sync_notifiers.read();
    let peers_notified = notifiers.len();

    for notify in notifiers.iter() {
        notify.notify_one();
    }

    info!(peers_notified, "Force sync triggered for all anti-entropy workers");

    Ok(Json(ForceSyncResponse {
        triggered: true,
        peers_notified,
        message: format!("Anti-entropy sync triggered for {} peer(s)", peers_notified),
    }))
}

/// GET /metrics - Prometheus metrics in text format.
///
/// Returns all registered metrics in Prometheus exposition format.
/// This endpoint bypasses all middleware to ensure metrics are always accessible.
pub async fn handle_metrics(
    handle: axum::extract::Extension<Arc<PrometheusHandle>>,
) -> impl IntoResponse {
    handle.render()
}
