//! Core types for Aphoria.

mod claim;
mod command;
mod language;
mod result;
mod verdict;

// Re-export all public types to maintain the same API
pub use claim::{ConflictingSource, ExtractedClaim, PolicySourceInfo};
pub use command::{AcknowledgeArgs, BlessArgs, FileSource, ScanArgs, ScanMode, UpdateArgs};
pub use language::Language;
pub use result::{
    ConflictResult, ConflictTrace, DeprecatedUsageResult, DriftResult, PriorObservation,
    ScanResult, ScanTiming,
};

pub use result::AcknowledgmentInfo;
pub use verdict::Verdict;

/// A set of predicates that are semantically equivalent.
///
/// Used for predicate alias matching during conflict detection.
/// For example, `enabled`, `required`, and `mandatory` might all be
/// semantically equivalent for a given security concept.
///
/// # Example
///
/// ```
/// use aphoria::PredicateAliasSet;
///
/// let aliases = PredicateAliasSet::new("enabled", vec!["required", "mandatory"]);
/// assert!(aliases.contains("enabled"));
/// assert!(aliases.contains("required"));
/// assert_eq!(aliases.normalize("mandatory"), Some("enabled"));
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct PredicateAliasSet {
    /// Canonical predicate name (used as the normalized key).
    pub canonical: String,
    /// All aliases that map to this canonical name.
    pub aliases: Vec<String>,
}

impl PredicateAliasSet {
    /// Create a new predicate alias set.
    pub fn new(canonical: impl Into<String>, aliases: Vec<impl Into<String>>) -> Self {
        Self { canonical: canonical.into(), aliases: aliases.into_iter().map(Into::into).collect() }
    }

    /// Check if this set contains the given predicate.
    pub fn contains(&self, predicate: &str) -> bool {
        self.canonical == predicate || self.aliases.iter().any(|a| a == predicate)
    }

    /// Normalize a predicate to its canonical form.
    ///
    /// Returns `Some(&canonical)` if the predicate is in this set,
    /// `None` otherwise.
    pub fn normalize(&self, predicate: &str) -> Option<&str> {
        if self.contains(predicate) {
            Some(&self.canonical)
        } else {
            None
        }
    }
}

/// Standard predicate strings used in Aphoria assertions.
///
/// Using constants instead of magic strings ensures consistency
/// and enables compile-time checking of predicate names.
pub mod predicates {
    /// Predicate for acknowledged conflicts (user has reviewed and accepted).
    pub const ACKNOWLEDGED: &str = "acknowledged";

    /// Predicate for blessed assertions (authoritative standards from `bless` command).
    pub const BLESSED: &str = "blessed";

    /// Predicate for Tier 4 observations (project memory from code scans).
    pub const OBSERVATION: &str = "observation";

    /// Predicate for intentional policy updates (from `update` command).
    pub const POLICY_UPDATE: &str = "policy_update";

    /// Predicate index key for imported authoritative assertions (from Trust Packs).
    /// These are assertions imported via `policy import` that should be used for
    /// conflict detection during scans.
    pub const AUTHORITATIVE: &str = "authoritative";
}

/// Extract the leaf concept (last segment after "//") from a concept path.
///
/// # Examples
///
/// ```
/// use aphoria::extract_leaf_concept;
///
/// assert_eq!(extract_leaf_concept("code://rust/myapp/tls/cert_verification"), "rust/myapp/tls/cert_verification");
/// assert_eq!(extract_leaf_concept("simple/path"), "simple/path");
/// ```
pub fn extract_leaf_concept(path: &str) -> &str {
    path.rsplit("//").next().unwrap_or(path)
}
