use crate::extract::{Extractor, InternalAuth};
use crate::EternaltwinSystem;
use axum::body::Body;
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use axum::routing::post;
use axum::{Extension, Json, Router};
use eternaltwin_core::oauth::{OauthClient, UpsertSystemClientOptions};
use serde_json::json;
use thiserror::Error;

pub fn router() -> Router<(), Body> {
  Router::new().route("/", post(upsert_system_client))
}

#[derive(Debug, Error)]
enum UpsertSystemClientError {
  #[error("internal error")]
  Internal,
}

impl From<eternaltwin_core::oauth::UpsertSystemClientError> for UpsertSystemClientError {
  fn from(inner: eternaltwin_core::oauth::UpsertSystemClientError) -> Self {
    use eternaltwin_core::oauth::UpsertSystemClientError::*;
    match inner {
      Other(_) => Self::Internal,
      InternalGetOwner(_) => Self::Internal,
    }
  }
}

impl IntoResponse for UpsertSystemClientError {
  fn into_response(self) -> Response {
    let status = match &self {
      Self::Internal => StatusCode::INTERNAL_SERVER_ERROR,
    };
    (status, Json(json!({ "error": self.to_string() }))).into_response()
  }
}

async fn upsert_system_client(
  Extension(api): Extension<EternaltwinSystem>,
  _auth: Extractor<InternalAuth>,
  Json(body): Json<UpsertSystemClientOptions>,
) -> Result<Json<OauthClient>, UpsertSystemClientError> {
  Ok(Json(api.oauth.upsert_system_client(&body).await?))
}
