use crate::RouterApi;
use axum::body::Body;
use axum::extract::{Extension, Path};
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use axum::routing::get;
use axum::{Json, Router};
use etwin_core::auth::AuthContext;
use etwin_core::twinoid::{EtwinTwinoidUser, GetTwinoidUserOptions, TwinoidUserId};
use serde::Serialize;
use serde_json::json;

pub fn router() -> Router<Body> {
  Router::new().route("/users/:user_id", get(get_user))
}

#[derive(Copy, Clone, Debug, Serialize)]
#[serde(tag = "error")]
enum GetTwinoidUserError {
  TwinoidUserNotFound,
  InternalServerError,
}

impl IntoResponse for GetTwinoidUserError {
  fn into_response(self) -> Response {
    let status = match self {
      Self::TwinoidUserNotFound => StatusCode::NOT_FOUND,
      Self::InternalServerError => StatusCode::INTERNAL_SERVER_ERROR,
    };
    let (status, body) = match serde_json::to_value(self) {
      Ok(body) => (status, Json(body)),
      Err(_) => (
        StatusCode::INTERNAL_SERVER_ERROR,
        Json(json!({"error": "InternalServerError"})),
      ),
    };
    (status, body).into_response()
  }
}

async fn get_user(
  Extension(api): Extension<RouterApi>,
  Path(id): Path<TwinoidUserId>,
) -> Result<Json<EtwinTwinoidUser>, GetTwinoidUserError> {
  use etwin_services::twinoid::GetUserError;

  let acx = AuthContext::guest();
  match api
    .twinoid
    .get_user(&acx, &GetTwinoidUserOptions { id, time: None })
    .await
  {
    Ok(result) => Ok(Json(result)),
    Err(GetUserError::NotFound) => Err(GetTwinoidUserError::TwinoidUserNotFound),
    Err(GetUserError::Other(_)) => Err(GetTwinoidUserError::InternalServerError),
  }
}
