use crate::ManagedRing;
use crate::RingspaceError;
use crate::db;
use rocket::State;
use serde_json::{Value, to_value};

///
/// [Responder] error type for manifest generation
///
#[derive(Responder)]
pub enum ManifestError {
    #[response(status = 500, content_type = "plain")]
    Error(String),
    #[response(status = 404, content_type = "plain")]
    NotFound(String),
}

impl From<sqlx::Error> for ManifestError {
    fn from(e: sqlx::Error) -> ManifestError {
        match e {
            sqlx::Error::RowNotFound => ManifestError::NotFound(
                "Ring does not exist (is a ring set as default?)".to_string(),
            ),
            _ => ManifestError::Error("Database Error".to_string()),
        }
    }
}

impl From<RingspaceError> for ManifestError {
    fn from(_: RingspaceError) -> ManifestError {
        ManifestError::Error("Manifest Creation Error".to_string())
    }
}

impl From<serde_json::Error> for ManifestError {
    fn from(_: serde_json::Error) -> ManifestError {
        ManifestError::Error("JSON Creation Error".to_string())
    }
}

///
/// Generates and returns the JSON manifest for the ring on demand.
///
#[get("/manifest")]
pub async fn get_manifest(ring: &State<ManagedRing>) -> Result<Value, ManifestError> {
    let mut conn = db::get_db_connection().await?;
    let ring = ring.inner();
    let manifest = ring.manifest(&mut conn).await?;
    let mut manifest_value = to_value(manifest)?;
    manifest_value.sort_all_objects();
    Ok(manifest_value)
}
