use gatekeep::Presence;
use keepsake::{
EffectiveRelationError, FulfillmentEvidence, LifecycleState, ObservationTime, RelationSnapshot,
effective_state,
};
use crate::KeepsakeRelationTarget;
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
pub enum EffectiveFactError {
#[error("effective relation observation scope mismatch")]
ScopeMismatch,
#[error("fulfillment evidence scope mismatch")]
FulfillmentScopeMismatch,
#[error(transparent)]
Evidence(#[from] EffectiveRelationError),
}
impl KeepsakeRelationTarget {
pub fn effective_presence(
&self,
time: ObservationTime,
snapshot: &RelationSnapshot,
fulfillment: Option<&FulfillmentEvidence>,
) -> Result<Presence, EffectiveFactError> {
time.instant()?;
if snapshot.tenant_id() != &self.tenant_id
|| snapshot.subject() != &self.subject
|| snapshot.relation_id() != self.relation_id
{
return Err(EffectiveFactError::ScopeMismatch);
}
let Some(active) = snapshot.active() else {
return if fulfillment.is_some() {
Err(EffectiveFactError::FulfillmentScopeMismatch)
} else {
Ok(Presence::Absent)
};
};
if let Some(evidence) = fulfillment
&& (evidence.tenant_id() != active.keepsake().tenant_id()
|| evidence.keepsake_id() != active.keepsake().id())
{
return Err(EffectiveFactError::FulfillmentScopeMismatch);
}
let fulfillment = fulfillment.map(FulfillmentEvidence::snapshot);
Ok(
if effective_state(time, active, fulfillment)? == LifecycleState::Applied {
Presence::Present
} else {
Presence::Absent
},
)
}
}