//! `VerifiedTrustState` — the output of the trusted-evidence reducer.

use cortex_core::ClaimCeiling;
use serde::{Deserialize, Serialize};

use crate::witness::WitnessSummary;

/// Failing edge for `VerifiedTrustState::Broken`. `invariant` is a stable
/// string from [`crate::invariant`]; `detail` is a human-readable explanation
/// for operators and logs.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BrokenEdge {
    /// Stable invariant name (e.g. `verifier.witness.disagreement`).
    pub invariant: String,
    /// Operator-readable detail string.
    pub detail: String,
}

impl BrokenEdge {
    /// Construct a `BrokenEdge` with a stable invariant name and a detail string.
    #[must_use]
    pub fn new(invariant: &'static str, detail: impl Into<String>) -> Self {
        Self {
            invariant: invariant.to_string(),
            detail: detail.into(),
        }
    }
}

/// One of three outcomes per ADR 0041 §"Stable failure taxonomy".
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "state", rename_all = "snake_case")]
pub enum VerifiedTrustState {
    /// Every required witness class is present, disjoint, fresh, well-tiered,
    /// and signature-valid. The verifier promotes the claim to the given
    /// effective ceiling.
    FullChainVerified {
        /// Effective ceiling the claim is allowed at.
        ceiling: ClaimCeiling,
        /// Summary of every witness that contributed.
        witnesses: Vec<WitnessSummary>,
    },
    /// Some required witness class is missing or insufficient, but no edge
    /// outright failed. Advisory-only; cannot promote.
    Partial {
        /// Per-axis reasons the partial result was emitted.
        reasons: Vec<String>,
        /// Summary of every witness that did pass.
        witnesses: Vec<WitnessSummary>,
    },
    /// A required axis outright failed (digest mismatch, stale, domain overlap,
    /// signature invalid, ceiling below required, policy fail-closed).
    Broken {
        /// Exact failing edge with stable invariant name.
        edge: BrokenEdge,
        /// Summary of every witness that was supplied. Useful for diagnosis.
        witnesses: Vec<WitnessSummary>,
    },
}

impl VerifiedTrustState {
    /// True iff this is `FullChainVerified`.
    #[must_use]
    pub const fn is_full_chain_verified(&self) -> bool {
        matches!(self, Self::FullChainVerified { .. })
    }

    /// True iff this is `Broken { .. }`.
    #[must_use]
    pub const fn is_broken(&self) -> bool {
        matches!(self, Self::Broken { .. })
    }

    /// True iff this is `Partial { .. }`.
    #[must_use]
    pub const fn is_partial(&self) -> bool {
        matches!(self, Self::Partial { .. })
    }

    /// Stable wire string for the variant (`full_chain_verified`, `partial`,
    /// or `broken`).
    #[must_use]
    pub const fn wire_str(&self) -> &'static str {
        match self {
            Self::FullChainVerified { .. } => "full_chain_verified",
            Self::Partial { .. } => "partial",
            Self::Broken { .. } => "broken",
        }
    }
}
