use std::collections::HashMap;
use parking_lot::Mutex;
use serde_json::{Value, json};
use toolkit_macros::domain_model;
use uuid::Uuid;
use account_management_sdk::{IdpNewUser, IdpProvisionTarget, IdpProvisionTenantRequest, IdpUser};
#[domain_model]
pub struct Service {
users: Mutex<HashMap<Uuid, HashMap<Uuid, IdpUser>>>,
}
impl Service {
#[must_use]
pub fn new() -> Self {
Self {
users: Mutex::new(HashMap::new()),
}
}
#[must_use]
pub fn echo_tenant_metadata(req: &IdpProvisionTenantRequest) -> Value {
let (target, parent_id) = match &req.target {
IdpProvisionTarget::Root => ("root", Value::Null),
IdpProvisionTarget::Child { parent_id } => ("child", json!(parent_id)),
_ => ("unknown", Value::Null),
};
json!({
"echo": true,
"tenant_id": req.tenant_id,
"tenant_name": req.name,
"tenant_type": req.tenant_type.as_ref(),
"target": target,
"parent_id": parent_id,
"provisioning_metadata": req.metadata.clone().unwrap_or(Value::Null),
})
}
#[must_use]
pub fn echo_user(tenant_id: Uuid, payload: &IdpNewUser) -> IdpUser {
let namespace = Uuid::new_v5(&Uuid::NAMESPACE_DNS, tenant_id.as_bytes());
let id = Uuid::new_v5(&namespace, payload.username.as_bytes());
let mut user = IdpUser::new(id, payload.username.clone());
if let Some(email) = &payload.email {
user = user.with_email(email.clone());
}
if let Some(display_name) = &payload.display_name {
user = user.with_display_name(display_name.clone());
}
if let Some(first_name) = &payload.first_name {
user = user.with_first_name(first_name.clone());
}
if let Some(last_name) = &payload.last_name {
user = user.with_last_name(last_name.clone());
}
user
}
pub fn record_user(&self, tenant_id: Uuid, user: IdpUser) {
self.users
.lock()
.entry(tenant_id)
.or_default()
.insert(user.id, user);
}
pub fn forget_user(&self, tenant_id: Uuid, user_id: Uuid) -> bool {
let mut guard = self.users.lock();
let Some(scope) = guard.get_mut(&tenant_id) else {
return false;
};
let removed = scope.remove(&user_id).is_some();
if scope.is_empty() {
guard.remove(&tenant_id);
}
removed
}
#[must_use]
pub fn snapshot_users(&self, tenant_id: Uuid) -> Vec<IdpUser> {
self.users
.lock()
.get(&tenant_id)
.map(|scope| scope.values().cloned().collect())
.unwrap_or_default()
}
}
impl Default for Service {
fn default() -> Self {
Self::new()
}
}