use std::collections::HashSet; use uuid::Uuid; use crate::error::{AppError, AppResult}; use super::CorrespondentAssignmentInput; pub const CORRESPONDENT_ROLES: &[&str] = &["sender", "receiver", "other"]; pub fn normalize_role(value: &str) -> String { value.trim().to_lowercase() } pub fn is_valid_correspondent_role(role: &str) -> bool { CORRESPONDENT_ROLES.iter().any(|allowed| *allowed == role) } pub fn normalize_correspondent_assignments( assignments: &[CorrespondentAssignmentInput], ) -> AppResult<(Vec<(Uuid, String)>, Vec, Vec)> { let mut unique_pairs: HashSet<(Uuid, String)> = HashSet::new(); let mut normalized_pairs: Vec<(Uuid, String)> = Vec::new(); let mut role_set: HashSet = HashSet::new(); let mut correspondent_ids: HashSet = HashSet::new(); for assignment in assignments { let role = normalize_role(&assignment.role); if role.is_empty() { return Err(AppError::bad_request("role must not be empty")); } if !is_valid_correspondent_role(&role) { return Err(AppError::bad_request(format!( "invalid correspondent role '{role}'. Allowed roles: {}", CORRESPONDENT_ROLES.join(", ") ))); } if !unique_pairs.insert((assignment.correspondent_id, role.clone())) { continue; } normalized_pairs.push((assignment.correspondent_id, role.clone())); role_set.insert(role); correspondent_ids.insert(assignment.correspondent_id); } if normalized_pairs.is_empty() { return Err(AppError::bad_request( "assignments must contain at least one unique correspondent/role pair", )); } let mut correspondents_vec: Vec = correspondent_ids.into_iter().collect(); correspondents_vec.sort(); let mut roles_vec: Vec = role_set.into_iter().collect(); roles_vec.sort(); Ok((normalized_pairs, correspondents_vec, roles_vec)) }