//! The freshness/provenance envelope every agent-facing answer carries.
//!
//! The unit of exchange with an AI agent is context *plus* who said it, when
//! it was retrieved, how fresh it is, and whether anything is missing —
//! `retrieved_at`, a worst-case `freshness` state, a `partial` flag, and,
//! when a navigation-data snapshot backed the answer, its cycle and verified
//! content hash. Every surface (MCP, FFI, in-process) assembles the same
//! envelope from these types; freshness states come from [`crate::freshness`].

use chrono::{DateTime, Utc};
use serde::Serialize;

use crate::freshness::Freshness;
use crate::navdata::NavDataCycle;

/// Machine-readable freshness + provenance for a tool's answer.
#[derive(Debug, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Provenance {
    /// When this server retrieved the data (RFC 3339, UTC).
    pub retrieved_at: String,
    /// Worst-case freshness across the answer's items: `current`, `stale`, or
    /// `unknown`. One stale item makes the whole answer `stale`.
    pub freshness: String,
    /// True when at least one source or route tile failed, so the result is
    /// incomplete — treat an absence as "unknown", not "none".
    pub partial: bool,
    /// Navdata cycle + content fingerprint, when a navigation-data snapshot
    /// backed this answer.
    pub navdata: Option<NavdataProvenance>,
}

impl Provenance {
    /// Build the envelope from an injected `now`, the rolled-up `freshness`,
    /// the `partial` flag, and optional navdata provenance.
    #[must_use]
    pub fn new(
        now: DateTime<Utc>,
        freshness: Freshness,
        partial: bool,
        navdata: Option<NavdataProvenance>,
    ) -> Self {
        Self {
            retrieved_at: now.to_rfc3339(),
            freshness: freshness.as_str().to_owned(),
            partial,
            navdata,
        }
    }
}

/// Provenance of the navigation-data snapshot behind an answer.
#[derive(Debug, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct NavdataProvenance {
    /// Effective range of the snapshot, `YYYY-MM-DD..YYYY-MM-DD`.
    pub cycle: String,
    /// Cycle freshness: `current` within the AIRAC window, else `stale`.
    pub freshness: String,
    /// Lowercase-hex SHA-256 of the navdata blob payload, verified on decode.
    pub sha256: String,
}

impl NavdataProvenance {
    /// Build from the snapshot's `cycle`, its already-classified `freshness`,
    /// and the blob's content `sha256`.
    #[must_use]
    pub fn new(cycle: &NavDataCycle, freshness: Freshness, sha256: String) -> Self {
        Self {
            cycle: format!("{}..{}", cycle.effective_on, cycle.next_effective_on),
            freshness: freshness.as_str().to_owned(),
            sha256,
        }
    }
}

#[cfg(test)]
mod tests;
