use axum::{
    extract::{Path, State},
    http::StatusCode,
    response::IntoResponse,
    Json,
};
use ontoref_derive::onto_api;
use serde::Serialize;
use vapora_channels::{ChannelError, Message};
use vapora_shared::VaporaError;

use crate::api::state::AppState;
use crate::api::ApiResult;

#[derive(Serialize)]
struct ChannelListResponse {
    channels: Vec<String>,
}

/// List all registered notification channels.
///
/// GET /api/v1/channels
#[onto_api(
    method = "GET",
    path = "/api/v1/channels",
    description = "Returns the names of all registered notification channels.",
    auth = "bearer",
    actors = "developer, admin",
    tags = "channels, read"
)]
pub async fn list_channels(State(state): State<AppState>) -> impl IntoResponse {
    let names = match &state.channel_registry {
        Some(r) => {
            let mut names: Vec<String> = r.channel_names().into_iter().map(str::to_owned).collect();
            names.sort_unstable();
            names
        }
        None => vec![],
    };
    Json(ChannelListResponse { channels: names })
}

/// Send a test message to a specific notification channel.
///
/// POST /api/v1/channels/:name/test
///
/// Returns 200 on successful delivery, 404 if the channel is unknown or not
/// configured, 502 if delivery fails at the remote platform.
#[onto_api(
    method = "POST",
    path = "/api/v1/channels/:name/test",
    description = "Sends a test message through the named notification channel to verify \
                   connectivity.",
    auth = "bearer",
    actors = "developer, admin",
    params = "name:string:required:Channel name",
    tags = "channels, write"
)]
pub async fn test_channel(
    State(state): State<AppState>,
    Path(name): Path<String>,
) -> ApiResult<impl IntoResponse> {
    let registry = state.channel_registry.as_ref().ok_or_else(|| {
        VaporaError::NotFound(format!(
            "Channel '{}' not found — no channels configured",
            name
        ))
    })?;

    let msg = Message::info(
        "Test notification",
        format!("Connectivity test from VAPORA backend for channel '{name}'"),
    );

    registry.send(&name, msg).await.map_err(|e| match e {
        ChannelError::NotFound(_) => VaporaError::NotFound(e.to_string()),
        other => VaporaError::InternalError(other.to_string()),
    })?;

    Ok(StatusCode::OK)
}
