BareGit
//! Durable and Matrix-facing data types for the foundation phase.

use serde::{Deserialize, Serialize};

/// Represents one normalized Matrix text message in an invocation's context.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct MatrixMessage {
    /// Matrix event ID that identifies this message.
    pub event_id: String,
    /// Matrix room ID containing this message.
    pub room_id: String,
    /// Stable Matrix user ID of the author.
    pub sender_id: String,
    /// Matrix server timestamp for chronological ordering.
    pub timestamp_ms: u64,
    /// Normalized text with meaningful formatting represented safely.
    pub body: String,
    /// Rich-reply target, when present.
    pub reply_to_event_id: Option<String>,
}

/// Identifies one candidate Matrix event that may invoke Lisa.
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct InvocationCandidate {
    /// Matrix event ID that uniquely identifies the invocation.
    pub event_id: String,
    /// Matrix room ID containing the event.
    pub room_id: String,
    /// Matrix user ID that sent the event.
    pub sender_id: String,
    /// Server timestamp recorded for ordering and diagnosis.
    pub received_at_ms: u64,
    /// Original Matrix event retained only until classification completes.
    pub raw_event_json: String,
    /// Deterministic Matrix transaction ID for Lisa's reply.
    pub matrix_txn_id: String,
}

/// Describes the durable stage of an invocation.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum InvocationStatus {
    /// The event awaits classification or processing.
    Candidate,
    /// A worker owns the event until its lease expires.
    Processing,
    /// The event cannot invoke Lisa.
    Ignored,
    /// A fixed reply payload is ready for idempotent Matrix delivery.
    ReadyToSend,
    /// Matrix accepted the reply and its event ID was recorded.
    Sent,
}

impl InvocationStatus {
    /// Returns the SQLite representation of this status.
    #[must_use]
    pub const fn as_str(self) -> &'static str {
        match self {
            Self::Candidate => "candidate",
            Self::Processing => "processing",
            Self::Ignored => "ignored",
            Self::ReadyToSend => "ready_to_send",
            Self::Sent => "sent",
        }
    }

    /// Parses a durable invocation status.
    pub fn parse(value: &str) -> Result<Self, String> {
        match value {
            "candidate" => Ok(Self::Candidate),
            "processing" => Ok(Self::Processing),
            "ignored" => Ok(Self::Ignored),
            "ready_to_send" => Ok(Self::ReadyToSend),
            "sent" => Ok(Self::Sent),
            _ => Err(format!("unknown invocation status {value:?}")),
        }
    }
}

/// Holds a durable invocation row exposed to workers.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct InvocationRecord {
    /// Matrix event ID that identifies the invocation.
    pub event_id: String,
    /// Matrix room ID containing the invocation.
    pub room_id: String,
    /// Matrix user ID that sent the invocation.
    pub sender_id: String,
    /// Server timestamp recorded for ordering.
    pub received_at_ms: u64,
    /// Current durable lifecycle state.
    pub status: InvocationStatus,
    /// Stored Matrix event JSON, absent after a terminal state.
    pub raw_event_json: Option<String>,
    /// Exact reply JSON persisted before delivery.
    pub response_json: Option<String>,
    /// Deterministic Matrix transaction ID.
    pub matrix_txn_id: String,
    /// Matrix event ID of Lisa's accepted reply.
    pub sent_event_id: Option<String>,
    /// Number of times a worker has acquired the invocation.
    pub attempt_count: u32,
    /// Time after which the row may be processed again.
    pub available_at_ms: u64,
    /// Stable non-sensitive error code for operators.
    pub last_error_code: Option<String>,
}

/// Holds Lisa's persisted controlled-sync position.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SyncState {
    /// Indicates whether the historical first-sync baseline was recorded.
    pub initialized: bool,
    /// Matrix next-batch token, if an initial sync has completed.
    pub next_batch: Option<String>,
}

/// Summarizes non-sensitive durable work for a local operator health check.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct HealthSnapshot
{
    /// Number of accepted candidates not currently leased by a worker.
    pub candidate_count: u64,
    /// Number of replies durably awaiting Matrix delivery.
    pub ready_to_send_count: u64,
    /// Age in milliseconds of the oldest reply awaiting delivery.
    pub oldest_ready_age_ms: Option<u64>,
}