use async_trait::async_trait;
use turnframe_core::case::CaseKey;
use turnframe_core::error::StoreError;
use turnframe_core::ids::{ConversationId, OriginToken, WorkflowKey};
use turnframe_core::turn::ActorContext;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CaseCandidate {
pub key: CaseKey,
pub label: String,
pub confirm_every_write: bool,
pub subject_only_when_named: bool,
}
impl CaseCandidate {
#[must_use]
pub fn new(key: CaseKey, label: impl Into<String>) -> Self {
Self {
key,
label: label.into(),
confirm_every_write: false,
subject_only_when_named: false,
}
}
#[must_use]
pub const fn confirming_every_write(mut self) -> Self {
self.confirm_every_write = true;
self
}
#[must_use]
pub const fn subject_only_when_named(mut self) -> Self {
self.subject_only_when_named = true;
self
}
}
#[async_trait]
pub trait CaseDirectory: Send + Sync {
async fn candidates(
&self,
actor: &ActorContext,
conversation: &ConversationId,
) -> Result<Vec<CaseCandidate>, StoreError>;
async fn authorize_case(
&self,
actor: &ActorContext,
conversation: &ConversationId,
key: &CaseKey,
) -> Result<Option<CaseCandidate>, StoreError> {
let _ = (actor, conversation, key);
Ok(None)
}
async fn find(
&self,
actor: &ActorContext,
conversation: &ConversationId,
workflow: &WorkflowKey,
named: Option<&str>,
) -> Result<Vec<CaseCandidate>, StoreError> {
let _ = (actor, conversation, workflow, named);
Ok(Vec::new())
}
async fn resolve_origin(
&self,
actor: &ActorContext,
origin: &OriginToken,
) -> Result<Option<CaseCandidate>, StoreError> {
let _ = (actor, origin);
Ok(None)
}
}
#[derive(Debug, Clone, Default)]
pub struct StaticCaseDirectory {
candidates: Vec<CaseCandidate>,
origins: Vec<(OriginToken, CaseCandidate)>,
}
impl StaticCaseDirectory {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn with_case(mut self, candidate: CaseCandidate) -> Self {
self.candidates.push(candidate);
self
}
#[must_use]
pub fn with_origin(mut self, origin: OriginToken, candidate: CaseCandidate) -> Self {
self.origins.push((origin, candidate));
self
}
}
#[async_trait]
impl CaseDirectory for StaticCaseDirectory {
async fn candidates(
&self,
_actor: &ActorContext,
_conversation: &ConversationId,
) -> Result<Vec<CaseCandidate>, StoreError> {
Ok(self.candidates.clone())
}
async fn resolve_origin(
&self,
_actor: &ActorContext,
origin: &OriginToken,
) -> Result<Option<CaseCandidate>, StoreError> {
Ok(self
.origins
.iter()
.find(|(token, _)| token == origin)
.map(|(_, candidate)| candidate.clone()))
}
}