//! Selection audit structures for context packs.

use serde::{Deserialize, Serialize};

use crate::pack::ContextRefId;
use crate::redaction::{PackMode, RedactionPolicy, Sensitivity};

/// Why a candidate ref was omitted from a context pack.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ExclusionReason {
    /// Omitted because it conflicts with selected or current intent.
    Contradiction,
    /// Omitted because it is stale for this task.
    Staleness,
    /// Omitted because it is outside task scope.
    ScopeMismatch,
    /// Omitted to preserve the requested token budget.
    TokenBudget,
    /// Omitted by redaction/privacy policy.
    RedactionPolicy,
    /// Omitted because current operator intent overrides historical pressure.
    CurrentIntent,
    /// Omitted for another explicitly recorded reason.
    Other,
}

/// Audit entry for a selected ref.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct IncludedAuditEntry {
    /// Included ref.
    pub ref_id: ContextRefId,
    /// Deterministic rule or policy id that selected it.
    pub rule_id: String,
    /// Human-readable reason recorded for audit.
    pub reason: String,
    /// Sensitivity tier used during selection.
    pub sensitivity: Sensitivity,
}

/// Audit entry for an excluded ref.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ExcludedAuditEntry {
    /// Excluded ref when policy permits recording the identifier.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub ref_id: Option<ContextRefId>,
    /// Ref kind retained even when the identifier is redacted.
    pub ref_kind: String,
    /// Exclusion reason.
    pub reason: ExclusionReason,
    /// Deterministic rule or policy id that excluded it.
    pub rule_id: String,
    /// Human-readable rationale.
    pub rationale: String,
    /// Sensitivity tier used during selection.
    pub sensitivity: Sensitivity,
}

/// Replayable audit data for pack construction.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SelectionAudit {
    /// Pack mode used during construction.
    pub pack_mode: PackMode,
    /// Redaction policy used during construction.
    pub redaction_policy: RedactionPolicy,
    /// Audit entries for included refs.
    pub included: Vec<IncludedAuditEntry>,
    /// Audit entries for excluded refs.
    pub exclusions: Vec<ExcludedAuditEntry>,
    /// Estimated token count from the local deterministic estimator.
    pub estimated_tokens: usize,
}

impl SelectionAudit {
    /// Construct an empty audit for a pack build.
    #[must_use]
    pub fn new(
        pack_mode: PackMode,
        redaction_policy: RedactionPolicy,
        estimated_tokens: usize,
    ) -> Self {
        Self {
            pack_mode,
            redaction_policy,
            included: Vec::new(),
            exclusions: Vec::new(),
            estimated_tokens,
        }
    }
}
