use axum::Json;
use axum::extract::{Path, State};
use axum::http::StatusCode;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use vta_sdk::protocols::members::{MEMBER_REQUEST_VMC_TYPE, RequestMemberVmcBody};
use vti_common::error::AppError;
use crate::auth::AdminAuth;
use crate::members::get_member;
use crate::server::AppState;
#[derive(Debug, Default, Deserialize)]
#[serde(rename_all = "camelCase")]
#[derive(utoipa::ToSchema)]
pub struct RequestVmcBody {
#[serde(default)]
pub reason: Option<String>,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
#[derive(utoipa::ToSchema)]
pub struct RequestVmcResponse {
pub member_did: String,
pub requested: bool,
pub thread_id: String,
}
#[utoipa::path(
post, path = "/members/{did}/request-vmc", tag = "members",
security(("bearer_jwt" = [])),
params(("did" = String, Path, description = "Member DID")),
request_body = RequestVmcBody,
responses(
(status = 202, description = "Request dispatched to the member", body = RequestVmcResponse),
(status = 404, description = "No active member with that DID"),
(status = 502, description = "Could not deliver the request to the member"),
),
)]
pub async fn request_vmc(
_auth: AdminAuth,
State(state): State<AppState>,
Path(member_did): Path<String>,
Json(body): Json<RequestVmcBody>,
) -> Result<(StatusCode, Json<RequestVmcResponse>), AppError> {
vti_common::identifier::validate_did("did", &member_did)?;
get_member(&state.members_ks, &member_did)
.await?
.filter(|m| !m.is_removed())
.ok_or_else(|| AppError::NotFound(format!("no active member: {member_did}")))?;
let community_did = state
.config
.read()
.await
.vtc_did
.clone()
.filter(|d| !d.is_empty())
.ok_or_else(|| {
AppError::Internal("VTC DID not configured — cannot request a member VMC".into())
})?;
let thread_id = Uuid::new_v4().to_string();
let request = RequestMemberVmcBody {
community_did,
reason: body.reason,
};
let request_body = serde_json::to_value(&request)
.map_err(|e| AppError::Internal(format!("serialise request-vmc body: {e}")))?;
crate::credentials::delivery::push_to_holder(
&state,
&member_did,
&thread_id,
MEMBER_REQUEST_VMC_TYPE,
request_body,
)
.await?;
Ok((
StatusCode::ACCEPTED,
Json(RequestVmcResponse {
member_did,
requested: true,
thread_id,
}),
))
}