// @generated — approval lifecycle authority for `ApprovalLifecycleMachine`
// Generated by `xtask protocol-codegen` from `ApprovalLifecycleMachine`.
#![allow(
    clippy::bool_comparison,
    clippy::field_reassign_with_default,
    clippy::never_loop,
    clippy::nonminimal_bool,
    clippy::partialeq_to_none,
    clippy::redundant_clone
)]

use std::{
    collections::{BTreeMap, BTreeSet},
    fmt,
};

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum ApprovalLifecycleStatus {
    #[default]
    Pending,
    Approved,
    Denied,
    Expired,
    Cancelled,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum ApprovalLifecycleDecision {
    #[default]
    Approve,
    Deny,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum ApprovalLifecycleRejectionReason {
    #[default]
    NotFound,
    AlreadyExists,
    AlreadyDecided,
    Expired,
    InvalidDecision,
    EmptyAllowedDecisions,
    InvalidRestoredRecord,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ApprovalLifecycleInput {
    CreateApproval {
        approval_id: String,
        approve_allowed: bool,
        deny_allowed: bool,
        has_expiry: bool,
    },
    RestoreApproval {
        approval_id: String,
        status: ApprovalLifecycleStatus,
        approve_allowed: bool,
        deny_allowed: bool,
        has_expiry: bool,
        decision: Option<ApprovalLifecycleDecision>,
    },
    ObserveApprovalExpiry {
        approval_id: String,
        expired: bool,
    },
    DecideApproval {
        approval_id: String,
        decision: ApprovalLifecycleDecision,
    },
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ApprovalLifecycleEffect {
    ApprovalStatusResolved {
        approval_id: String,
        status: ApprovalLifecycleStatus,
    },
    ApprovalLifecycleRejected {
        approval_id: String,
        reason: ApprovalLifecycleRejectionReason,
    },
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ApprovalLifecycleOutcome {
    Status(ApprovalLifecycleStatus),
    Rejected(ApprovalLifecycleRejectionReason),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ApprovalLifecycleError {
    op: &'static str,
}

impl fmt::Display for ApprovalLifecycleError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "generated approval lifecycle authority rejected {}",
            self.op
        )
    }
}

impl std::error::Error for ApprovalLifecycleError {}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum ApprovalLifecyclePhase {
    #[default]
    Ready,
}

#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct ApprovalLifecycleMachineState {
    lifecycle_phase: ApprovalLifecyclePhase,
    approval_ids: BTreeSet<String>,
    approval_statuses: BTreeMap<String, ApprovalLifecycleStatus>,
    approval_approve_allowed: BTreeMap<String, bool>,
    approval_deny_allowed: BTreeMap<String, bool>,
    approval_has_expiry: BTreeMap<String, bool>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ApprovalLifecycleTransition {
    CreateRejectedEmptyAllowedDecisions,
    CreateRejectedAlreadyExists,
    CreatePending,
    RestoreRejectedDuplicate,
    RestoreRejectedEmptyAllowedDecisions,
    RestorePending,
    RestoreExpired,
    RestoreCancelled,
    RestoreApproved,
    RestoreDenied,
    RestoreRejectedInvalidRecord,
    ObserveExpiryRejectedMissing,
    ObserveExpiryExpiresPending,
    ObserveExpiryPendingNoop,
    ObserveExpiryApprovedNoop,
    ObserveExpiryDeniedNoop,
    ObserveExpiryExpiredNoop,
    ObserveExpiryCancelledNoop,
    DecideRejectedMissing,
    DecideRejectedExpired,
    DecideRejectedAlreadyDecided,
    DecideRejectedApproveNotAllowed,
    DecideRejectedDenyNotAllowed,
    DecideApprove,
    DecideDeny,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ApprovalLifecycleMachineAuthority {
    state: ApprovalLifecycleMachineState,
}

impl ApprovalLifecycleMachineAuthority {
    #[must_use]
    pub fn new() -> Self {
        let mut state = ApprovalLifecycleMachineState::default();
        state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
        state.approval_ids = BTreeSet::new();
        state.approval_statuses = BTreeMap::new();
        state.approval_approve_allowed = BTreeMap::new();
        state.approval_deny_allowed = BTreeMap::new();
        state.approval_has_expiry = BTreeMap::new();
        Self { state }
    }

    #[must_use]
    pub fn state(&self) -> &ApprovalLifecycleMachineState {
        &self.state
    }

    #[must_use]
    pub fn status_for(&self, approval_id: &str) -> Option<ApprovalLifecycleStatus> {
        self.state.approval_statuses.get(approval_id).copied()
    }

    fn approval_statuses_value(
        &self,
        approval_id: &str,
    ) -> Result<ApprovalLifecycleStatus, ApprovalLifecycleError> {
        self.state
            .approval_statuses
            .get(approval_id)
            .copied()
            .ok_or(ApprovalLifecycleError {
                op: "approval_statuses",
            })
    }

    fn approval_approve_allowed_value(
        &self,
        approval_id: &str,
    ) -> Result<bool, ApprovalLifecycleError> {
        self.state
            .approval_approve_allowed
            .get(approval_id)
            .copied()
            .ok_or(ApprovalLifecycleError {
                op: "approval_approve_allowed",
            })
    }

    fn approval_deny_allowed_value(
        &self,
        approval_id: &str,
    ) -> Result<bool, ApprovalLifecycleError> {
        self.state
            .approval_deny_allowed
            .get(approval_id)
            .copied()
            .ok_or(ApprovalLifecycleError {
                op: "approval_deny_allowed",
            })
    }

    fn approval_has_expiry_value(&self, approval_id: &str) -> Result<bool, ApprovalLifecycleError> {
        self.state
            .approval_has_expiry
            .get(approval_id)
            .copied()
            .ok_or(ApprovalLifecycleError {
                op: "approval_has_expiry",
            })
    }

    fn single_transition(
        matches: Vec<ApprovalLifecycleTransition>,
        op: &'static str,
    ) -> Result<ApprovalLifecycleTransition, ApprovalLifecycleError> {
        let mut matches = matches.into_iter();
        let Some(first) = matches.next() else {
            return Err(ApprovalLifecycleError { op });
        };
        if matches.next().is_some() {
            return Err(ApprovalLifecycleError { op });
        }
        Ok(first)
    }

    fn apply_input(
        &mut self,
        input: ApprovalLifecycleInput,
    ) -> Result<Vec<ApprovalLifecycleEffect>, ApprovalLifecycleError> {
        match input {
            ApprovalLifecycleInput::CreateApproval {
                approval_id,
                approve_allowed,
                deny_allowed,
                has_expiry,
            } => {
                let mut matches = Vec::new();
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && (allowed_non_empty(approve_allowed, deny_allowed) == false)
                {
                    matches.push(ApprovalLifecycleTransition::CreateRejectedEmptyAllowedDecisions);
                }
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && ((allowed_non_empty(approve_allowed, deny_allowed))
                        && (self.state.approval_ids.contains(approval_id.as_str())))
                {
                    matches.push(ApprovalLifecycleTransition::CreateRejectedAlreadyExists);
                }
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && ((allowed_non_empty(approve_allowed, deny_allowed))
                        && (self.state.approval_ids.contains(approval_id.as_str()) == false))
                {
                    matches.push(ApprovalLifecycleTransition::CreatePending);
                }
                let transition = Self::single_transition(matches, "CreateApproval")?;
                match transition {
                    ApprovalLifecycleTransition::CreateRejectedEmptyAllowedDecisions => {
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalLifecycleRejected {
                            approval_id: approval_id.clone(),
                            reason: ApprovalLifecycleRejectionReason::EmptyAllowedDecisions,
                        }])
                    }
                    ApprovalLifecycleTransition::CreateRejectedAlreadyExists => {
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalLifecycleRejected {
                            approval_id: approval_id.clone(),
                            reason: ApprovalLifecycleRejectionReason::AlreadyExists,
                        }])
                    }
                    ApprovalLifecycleTransition::CreatePending => {
                        self.state.approval_ids.insert(approval_id.clone());
                        self.state
                            .approval_statuses
                            .insert(approval_id.clone(), ApprovalLifecycleStatus::Pending);
                        self.state
                            .approval_approve_allowed
                            .insert(approval_id.clone(), approve_allowed);
                        self.state
                            .approval_deny_allowed
                            .insert(approval_id.clone(), deny_allowed);
                        self.state
                            .approval_has_expiry
                            .insert(approval_id.clone(), has_expiry);
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalStatusResolved {
                            approval_id: approval_id.clone(),
                            status: ApprovalLifecycleStatus::Pending,
                        }])
                    }
                    _ => Err(ApprovalLifecycleError {
                        op: "CreateApproval_transition",
                    }),
                }
            }
            ApprovalLifecycleInput::RestoreApproval {
                approval_id,
                status,
                approve_allowed,
                deny_allowed,
                has_expiry,
                decision,
            } => {
                let mut matches = Vec::new();
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && (self.state.approval_ids.contains(approval_id.as_str()))
                {
                    matches.push(ApprovalLifecycleTransition::RestoreRejectedDuplicate);
                }
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && ((self.state.approval_ids.contains(approval_id.as_str()) == false)
                        && (allowed_non_empty(approve_allowed, deny_allowed) == false))
                {
                    matches.push(ApprovalLifecycleTransition::RestoreRejectedEmptyAllowedDecisions);
                }
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && ((self.state.approval_ids.contains(approval_id.as_str()) == false)
                        && (allowed_non_empty(approve_allowed, deny_allowed))
                        && (status == ApprovalLifecycleStatus::Pending)
                        && (decision == None))
                {
                    matches.push(ApprovalLifecycleTransition::RestorePending);
                }
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && ((self.state.approval_ids.contains(approval_id.as_str()) == false)
                        && (allowed_non_empty(approve_allowed, deny_allowed))
                        && (status == ApprovalLifecycleStatus::Expired)
                        && (decision == None))
                {
                    matches.push(ApprovalLifecycleTransition::RestoreExpired);
                }
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && ((self.state.approval_ids.contains(approval_id.as_str()) == false)
                        && (allowed_non_empty(approve_allowed, deny_allowed))
                        && (status == ApprovalLifecycleStatus::Cancelled)
                        && (decision == None))
                {
                    matches.push(ApprovalLifecycleTransition::RestoreCancelled);
                }
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && ((self.state.approval_ids.contains(approval_id.as_str()) == false)
                        && (allowed_non_empty(approve_allowed, deny_allowed))
                        && (approve_allowed)
                        && (status == ApprovalLifecycleStatus::Approved)
                        && (decision == Some(ApprovalLifecycleDecision::Approve)))
                {
                    matches.push(ApprovalLifecycleTransition::RestoreApproved);
                }
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && ((self.state.approval_ids.contains(approval_id.as_str()) == false)
                        && (allowed_non_empty(approve_allowed, deny_allowed))
                        && (deny_allowed)
                        && (status == ApprovalLifecycleStatus::Denied)
                        && (decision == Some(ApprovalLifecycleDecision::Deny)))
                {
                    matches.push(ApprovalLifecycleTransition::RestoreDenied);
                }
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && ((self.state.approval_ids.contains(approval_id.as_str()) == false)
                        && (allowed_non_empty(approve_allowed, deny_allowed))
                        && (((status == ApprovalLifecycleStatus::Pending) && (decision != None))
                            || ((status == ApprovalLifecycleStatus::Expired)
                                && (decision != None))
                            || ((status == ApprovalLifecycleStatus::Cancelled)
                                && (decision != None))
                            || ((status == ApprovalLifecycleStatus::Approved)
                                && ((approve_allowed == false)
                                    || (decision != Some(ApprovalLifecycleDecision::Approve))))
                            || ((status == ApprovalLifecycleStatus::Denied)
                                && ((deny_allowed == false)
                                    || (decision != Some(ApprovalLifecycleDecision::Deny))))))
                {
                    matches.push(ApprovalLifecycleTransition::RestoreRejectedInvalidRecord);
                }
                let transition = Self::single_transition(matches, "RestoreApproval")?;
                match transition {
                    ApprovalLifecycleTransition::RestoreRejectedDuplicate => {
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalLifecycleRejected {
                            approval_id: approval_id.clone(),
                            reason: ApprovalLifecycleRejectionReason::AlreadyExists,
                        }])
                    }
                    ApprovalLifecycleTransition::RestoreRejectedEmptyAllowedDecisions => {
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalLifecycleRejected {
                            approval_id: approval_id.clone(),
                            reason: ApprovalLifecycleRejectionReason::EmptyAllowedDecisions,
                        }])
                    }
                    ApprovalLifecycleTransition::RestorePending => {
                        self.state.approval_ids.insert(approval_id.clone());
                        self.state
                            .approval_statuses
                            .insert(approval_id.clone(), ApprovalLifecycleStatus::Pending);
                        self.state
                            .approval_approve_allowed
                            .insert(approval_id.clone(), approve_allowed);
                        self.state
                            .approval_deny_allowed
                            .insert(approval_id.clone(), deny_allowed);
                        self.state
                            .approval_has_expiry
                            .insert(approval_id.clone(), has_expiry);
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalStatusResolved {
                            approval_id: approval_id.clone(),
                            status: ApprovalLifecycleStatus::Pending,
                        }])
                    }
                    ApprovalLifecycleTransition::RestoreExpired => {
                        self.state.approval_ids.insert(approval_id.clone());
                        self.state
                            .approval_statuses
                            .insert(approval_id.clone(), ApprovalLifecycleStatus::Expired);
                        self.state
                            .approval_approve_allowed
                            .insert(approval_id.clone(), approve_allowed);
                        self.state
                            .approval_deny_allowed
                            .insert(approval_id.clone(), deny_allowed);
                        self.state
                            .approval_has_expiry
                            .insert(approval_id.clone(), has_expiry);
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalStatusResolved {
                            approval_id: approval_id.clone(),
                            status: ApprovalLifecycleStatus::Expired,
                        }])
                    }
                    ApprovalLifecycleTransition::RestoreCancelled => {
                        self.state.approval_ids.insert(approval_id.clone());
                        self.state
                            .approval_statuses
                            .insert(approval_id.clone(), ApprovalLifecycleStatus::Cancelled);
                        self.state
                            .approval_approve_allowed
                            .insert(approval_id.clone(), approve_allowed);
                        self.state
                            .approval_deny_allowed
                            .insert(approval_id.clone(), deny_allowed);
                        self.state
                            .approval_has_expiry
                            .insert(approval_id.clone(), has_expiry);
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalStatusResolved {
                            approval_id: approval_id.clone(),
                            status: ApprovalLifecycleStatus::Cancelled,
                        }])
                    }
                    ApprovalLifecycleTransition::RestoreApproved => {
                        self.state.approval_ids.insert(approval_id.clone());
                        self.state
                            .approval_statuses
                            .insert(approval_id.clone(), ApprovalLifecycleStatus::Approved);
                        self.state
                            .approval_approve_allowed
                            .insert(approval_id.clone(), approve_allowed);
                        self.state
                            .approval_deny_allowed
                            .insert(approval_id.clone(), deny_allowed);
                        self.state
                            .approval_has_expiry
                            .insert(approval_id.clone(), has_expiry);
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalStatusResolved {
                            approval_id: approval_id.clone(),
                            status: ApprovalLifecycleStatus::Approved,
                        }])
                    }
                    ApprovalLifecycleTransition::RestoreDenied => {
                        self.state.approval_ids.insert(approval_id.clone());
                        self.state
                            .approval_statuses
                            .insert(approval_id.clone(), ApprovalLifecycleStatus::Denied);
                        self.state
                            .approval_approve_allowed
                            .insert(approval_id.clone(), approve_allowed);
                        self.state
                            .approval_deny_allowed
                            .insert(approval_id.clone(), deny_allowed);
                        self.state
                            .approval_has_expiry
                            .insert(approval_id.clone(), has_expiry);
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalStatusResolved {
                            approval_id: approval_id.clone(),
                            status: ApprovalLifecycleStatus::Denied,
                        }])
                    }
                    ApprovalLifecycleTransition::RestoreRejectedInvalidRecord => {
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalLifecycleRejected {
                            approval_id: approval_id.clone(),
                            reason: ApprovalLifecycleRejectionReason::InvalidRestoredRecord,
                        }])
                    }
                    _ => Err(ApprovalLifecycleError {
                        op: "RestoreApproval_transition",
                    }),
                }
            }
            ApprovalLifecycleInput::ObserveApprovalExpiry {
                approval_id,
                expired,
            } => {
                let mut matches = Vec::new();
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && (self.state.approval_ids.contains(approval_id.as_str()) == false)
                {
                    matches.push(ApprovalLifecycleTransition::ObserveExpiryRejectedMissing);
                }
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && ((self.state.approval_ids.contains(approval_id.as_str()))
                        && (self.approval_statuses_value(approval_id.as_str())?
                            == ApprovalLifecycleStatus::Pending)
                        && (self.approval_has_expiry_value(approval_id.as_str())?)
                        && (expired))
                {
                    matches.push(ApprovalLifecycleTransition::ObserveExpiryExpiresPending);
                }
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && ((self.state.approval_ids.contains(approval_id.as_str()))
                        && (self.approval_statuses_value(approval_id.as_str())?
                            == ApprovalLifecycleStatus::Pending)
                        && ((self.approval_has_expiry_value(approval_id.as_str())? == false)
                            || (expired == false)))
                {
                    matches.push(ApprovalLifecycleTransition::ObserveExpiryPendingNoop);
                }
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && ((self.state.approval_ids.contains(approval_id.as_str()))
                        && (self.approval_statuses_value(approval_id.as_str())?
                            == ApprovalLifecycleStatus::Approved))
                {
                    matches.push(ApprovalLifecycleTransition::ObserveExpiryApprovedNoop);
                }
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && ((self.state.approval_ids.contains(approval_id.as_str()))
                        && (self.approval_statuses_value(approval_id.as_str())?
                            == ApprovalLifecycleStatus::Denied))
                {
                    matches.push(ApprovalLifecycleTransition::ObserveExpiryDeniedNoop);
                }
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && ((self.state.approval_ids.contains(approval_id.as_str()))
                        && (self.approval_statuses_value(approval_id.as_str())?
                            == ApprovalLifecycleStatus::Expired))
                {
                    matches.push(ApprovalLifecycleTransition::ObserveExpiryExpiredNoop);
                }
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && ((self.state.approval_ids.contains(approval_id.as_str()))
                        && (self.approval_statuses_value(approval_id.as_str())?
                            == ApprovalLifecycleStatus::Cancelled))
                {
                    matches.push(ApprovalLifecycleTransition::ObserveExpiryCancelledNoop);
                }
                let transition = Self::single_transition(matches, "ObserveApprovalExpiry")?;
                match transition {
                    ApprovalLifecycleTransition::ObserveExpiryRejectedMissing => {
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalLifecycleRejected {
                            approval_id: approval_id.clone(),
                            reason: ApprovalLifecycleRejectionReason::NotFound,
                        }])
                    }
                    ApprovalLifecycleTransition::ObserveExpiryExpiresPending => {
                        self.state
                            .approval_statuses
                            .insert(approval_id.clone(), ApprovalLifecycleStatus::Expired);
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalStatusResolved {
                            approval_id: approval_id.clone(),
                            status: ApprovalLifecycleStatus::Expired,
                        }])
                    }
                    ApprovalLifecycleTransition::ObserveExpiryPendingNoop => {
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalStatusResolved {
                            approval_id: approval_id.clone(),
                            status: ApprovalLifecycleStatus::Pending,
                        }])
                    }
                    ApprovalLifecycleTransition::ObserveExpiryApprovedNoop => {
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalStatusResolved {
                            approval_id: approval_id.clone(),
                            status: ApprovalLifecycleStatus::Approved,
                        }])
                    }
                    ApprovalLifecycleTransition::ObserveExpiryDeniedNoop => {
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalStatusResolved {
                            approval_id: approval_id.clone(),
                            status: ApprovalLifecycleStatus::Denied,
                        }])
                    }
                    ApprovalLifecycleTransition::ObserveExpiryExpiredNoop => {
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalStatusResolved {
                            approval_id: approval_id.clone(),
                            status: ApprovalLifecycleStatus::Expired,
                        }])
                    }
                    ApprovalLifecycleTransition::ObserveExpiryCancelledNoop => {
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalStatusResolved {
                            approval_id: approval_id.clone(),
                            status: ApprovalLifecycleStatus::Cancelled,
                        }])
                    }
                    _ => Err(ApprovalLifecycleError {
                        op: "ObserveApprovalExpiry_transition",
                    }),
                }
            }
            ApprovalLifecycleInput::DecideApproval {
                approval_id,
                decision,
            } => {
                let mut matches = Vec::new();
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && (self.state.approval_ids.contains(approval_id.as_str()) == false)
                {
                    matches.push(ApprovalLifecycleTransition::DecideRejectedMissing);
                }
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && ((self.state.approval_ids.contains(approval_id.as_str()))
                        && (self.approval_statuses_value(approval_id.as_str())?
                            == ApprovalLifecycleStatus::Expired))
                {
                    matches.push(ApprovalLifecycleTransition::DecideRejectedExpired);
                }
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && ((self.state.approval_ids.contains(approval_id.as_str()))
                        && (is_terminal_status(
                            self.approval_statuses_value(approval_id.as_str())?,
                        )))
                {
                    matches.push(ApprovalLifecycleTransition::DecideRejectedAlreadyDecided);
                }
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && ((self.state.approval_ids.contains(approval_id.as_str()))
                        && (self.approval_statuses_value(approval_id.as_str())?
                            == ApprovalLifecycleStatus::Pending)
                        && (decision == ApprovalLifecycleDecision::Approve)
                        && (self.approval_approve_allowed_value(approval_id.as_str())? == false))
                {
                    matches.push(ApprovalLifecycleTransition::DecideRejectedApproveNotAllowed);
                }
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && ((self.state.approval_ids.contains(approval_id.as_str()))
                        && (self.approval_statuses_value(approval_id.as_str())?
                            == ApprovalLifecycleStatus::Pending)
                        && (decision == ApprovalLifecycleDecision::Deny)
                        && (self.approval_deny_allowed_value(approval_id.as_str())? == false))
                {
                    matches.push(ApprovalLifecycleTransition::DecideRejectedDenyNotAllowed);
                }
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && ((self.state.approval_ids.contains(approval_id.as_str()))
                        && (self.approval_statuses_value(approval_id.as_str())?
                            == ApprovalLifecycleStatus::Pending)
                        && (decision == ApprovalLifecycleDecision::Approve)
                        && (self.approval_approve_allowed_value(approval_id.as_str())?))
                {
                    matches.push(ApprovalLifecycleTransition::DecideApprove);
                }
                if (self.state.lifecycle_phase == ApprovalLifecyclePhase::Ready)
                    && ((self.state.approval_ids.contains(approval_id.as_str()))
                        && (self.approval_statuses_value(approval_id.as_str())?
                            == ApprovalLifecycleStatus::Pending)
                        && (decision == ApprovalLifecycleDecision::Deny)
                        && (self.approval_deny_allowed_value(approval_id.as_str())?))
                {
                    matches.push(ApprovalLifecycleTransition::DecideDeny);
                }
                let transition = Self::single_transition(matches, "DecideApproval")?;
                match transition {
                    ApprovalLifecycleTransition::DecideRejectedMissing => {
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalLifecycleRejected {
                            approval_id: approval_id.clone(),
                            reason: ApprovalLifecycleRejectionReason::NotFound,
                        }])
                    }
                    ApprovalLifecycleTransition::DecideRejectedExpired => {
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalLifecycleRejected {
                            approval_id: approval_id.clone(),
                            reason: ApprovalLifecycleRejectionReason::Expired,
                        }])
                    }
                    ApprovalLifecycleTransition::DecideRejectedAlreadyDecided => {
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalLifecycleRejected {
                            approval_id: approval_id.clone(),
                            reason: ApprovalLifecycleRejectionReason::AlreadyDecided,
                        }])
                    }
                    ApprovalLifecycleTransition::DecideRejectedApproveNotAllowed => {
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalLifecycleRejected {
                            approval_id: approval_id.clone(),
                            reason: ApprovalLifecycleRejectionReason::InvalidDecision,
                        }])
                    }
                    ApprovalLifecycleTransition::DecideRejectedDenyNotAllowed => {
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalLifecycleRejected {
                            approval_id: approval_id.clone(),
                            reason: ApprovalLifecycleRejectionReason::InvalidDecision,
                        }])
                    }
                    ApprovalLifecycleTransition::DecideApprove => {
                        self.state
                            .approval_statuses
                            .insert(approval_id.clone(), ApprovalLifecycleStatus::Approved);
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalStatusResolved {
                            approval_id: approval_id.clone(),
                            status: ApprovalLifecycleStatus::Approved,
                        }])
                    }
                    ApprovalLifecycleTransition::DecideDeny => {
                        self.state
                            .approval_statuses
                            .insert(approval_id.clone(), ApprovalLifecycleStatus::Denied);
                        self.state.lifecycle_phase = ApprovalLifecyclePhase::Ready;
                        Ok(vec![ApprovalLifecycleEffect::ApprovalStatusResolved {
                            approval_id: approval_id.clone(),
                            status: ApprovalLifecycleStatus::Denied,
                        }])
                    }
                    _ => Err(ApprovalLifecycleError {
                        op: "DecideApproval_transition",
                    }),
                }
            }
        }
    }

    fn outcome_from_effects(
        effects: Vec<ApprovalLifecycleEffect>,
        op: &'static str,
    ) -> Result<ApprovalLifecycleOutcome, ApprovalLifecycleError> {
        for effect in effects {
            match effect {
                ApprovalLifecycleEffect::ApprovalStatusResolved { status, .. } => {
                    return Ok(ApprovalLifecycleOutcome::Status(status));
                }
                ApprovalLifecycleEffect::ApprovalLifecycleRejected { reason, .. } => {
                    return Ok(ApprovalLifecycleOutcome::Rejected(reason));
                }
            }
        }
        Err(ApprovalLifecycleError { op })
    }

    pub fn create_approval(
        &mut self,
        approval_id: String,
        approve_allowed: bool,
        deny_allowed: bool,
        has_expiry: bool,
    ) -> Result<ApprovalLifecycleOutcome, ApprovalLifecycleError> {
        let effects = self.apply_input(ApprovalLifecycleInput::CreateApproval {
            approval_id,
            approve_allowed,
            deny_allowed,
            has_expiry,
        })?;
        Self::outcome_from_effects(effects, "create_approval_effect")
    }

    pub fn restore_approval(
        &mut self,
        approval_id: String,
        status: ApprovalLifecycleStatus,
        approve_allowed: bool,
        deny_allowed: bool,
        has_expiry: bool,
        decision: Option<ApprovalLifecycleDecision>,
    ) -> Result<ApprovalLifecycleOutcome, ApprovalLifecycleError> {
        let effects = self.apply_input(ApprovalLifecycleInput::RestoreApproval {
            approval_id,
            status,
            approve_allowed,
            deny_allowed,
            has_expiry,
            decision,
        })?;
        Self::outcome_from_effects(effects, "restore_approval_effect")
    }

    pub fn observe_approval_expiry(
        &mut self,
        approval_id: String,
        expired: bool,
    ) -> Result<ApprovalLifecycleOutcome, ApprovalLifecycleError> {
        let effects = self.apply_input(ApprovalLifecycleInput::ObserveApprovalExpiry {
            approval_id,
            expired,
        })?;
        Self::outcome_from_effects(effects, "observe_approval_expiry_effect")
    }

    pub fn decide_approval(
        &mut self,
        approval_id: String,
        decision: ApprovalLifecycleDecision,
    ) -> Result<ApprovalLifecycleOutcome, ApprovalLifecycleError> {
        let effects = self.apply_input(ApprovalLifecycleInput::DecideApproval {
            approval_id,
            decision,
        })?;
        Self::outcome_from_effects(effects, "decide_approval_effect")
    }
}

fn allowed_non_empty(approve_allowed: bool, deny_allowed: bool) -> bool {
    (approve_allowed) || (deny_allowed)
}

fn is_terminal_status(status: ApprovalLifecycleStatus) -> bool {
    (status == ApprovalLifecycleStatus::Approved)
        || (status == ApprovalLifecycleStatus::Denied)
        || (status == ApprovalLifecycleStatus::Cancelled)
}

impl Default for ApprovalLifecycleMachineAuthority {
    fn default() -> Self {
        Self::new()
    }
}
