use crate::{DevApi, RouterApi};
use axum::body::Body;
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use axum::routing::get;
use axum::{Extension, Json, Router};
use etwin_core::core::Instant;
use serde::{Deserialize, Serialize};
use thiserror::Error;

pub fn router() -> Router<Body> {
  Router::new().route("/", get(get_clock).put(set_time))
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct RestClock {
  pub time: Instant,
}

async fn get_clock(Extension(api): Extension<RouterApi>) -> Json<RestClock> {
  Json(RestClock { time: api.clock.now() })
}

#[derive(Debug, Error)]
enum SetTimeError {
  #[error("dev clock API is disabled")]
  Disabled,
}

impl IntoResponse for SetTimeError {
  fn into_response(self) -> Response {
    (StatusCode::FORBIDDEN, self.to_string()).into_response()
  }
}

async fn set_time(
  Extension(dev_api): Extension<DevApi>,
  Json(body): Json<RestClock>,
) -> Result<(StatusCode, Json<RestClock>), SetTimeError> {
  let clock = dev_api.clock.ok_or(SetTimeError::Disabled)?;
  let new_time = clock.advance_to(body.time);
  Ok((StatusCode::OK, Json(RestClock { time: new_time })))
}
