//! Typed status enums for the three [`EvaluationBucket`] kinds.
//!
//! Each enum serializes to the exact snake_case tag the stringly-typed
//! predecessor emitted, so `RadarStateReport`'s public JSON shape is
//! preserved bit-for-bit. Consumer sites in `context_check` and
//! `session_boundary` work with typed enum values instead of raw string
//! literals — equality checks against variants, and `build_approval_steps`'s
//! `wrap_up` arm is an exhaustive match across `WrapUpStatus` — giving
//! compile-time guarantees that the radar-state regression tests in
//! `tests/cli.rs` previously caught only at runtime. The `render_text`
//! impl formats `WrapUpStatus` via `as_str()` for the one-line
//! operator-facing summary.
//!
//! [`EvaluationBucket`]: super::EvaluationBucket

use serde::Serialize;

#[derive(Serialize, Clone, Copy, Debug, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub(crate) enum NextStepStatus {
    Continue,
    ReviewRequired,
    NoChangeDetected,
    NoChange,
}

#[derive(Serialize, Clone, Copy, Debug, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub(crate) enum MemoryStatus {
    Loaded,
    NoCliSignal,
    ReviewRequired,
    NoChange,
}

#[derive(Serialize, Clone, Copy, Debug, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub(crate) enum WrapUpStatus {
    Clean,
    ReadyToCommit,
    ReadyToPush,
    NeedsReview,
    NoChange,
}

impl WrapUpStatus {
    pub(crate) fn as_str(self) -> &'static str {
        match self {
            Self::Clean => "clean",
            Self::ReadyToCommit => "ready_to_commit",
            Self::ReadyToPush => "ready_to_push",
            Self::NeedsReview => "needs_review",
            Self::NoChange => "no_change",
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn next_step_serializes_to_snake_case_contract() {
        assert_eq!(
            serde_json::to_string(&NextStepStatus::Continue).unwrap(),
            "\"continue\""
        );
        assert_eq!(
            serde_json::to_string(&NextStepStatus::ReviewRequired).unwrap(),
            "\"review_required\""
        );
        assert_eq!(
            serde_json::to_string(&NextStepStatus::NoChangeDetected).unwrap(),
            "\"no_change_detected\""
        );
        assert_eq!(
            serde_json::to_string(&NextStepStatus::NoChange).unwrap(),
            "\"no_change\""
        );
    }

    #[test]
    fn memory_serializes_to_snake_case_contract() {
        assert_eq!(
            serde_json::to_string(&MemoryStatus::Loaded).unwrap(),
            "\"loaded\""
        );
        assert_eq!(
            serde_json::to_string(&MemoryStatus::NoCliSignal).unwrap(),
            "\"no_cli_signal\""
        );
        assert_eq!(
            serde_json::to_string(&MemoryStatus::ReviewRequired).unwrap(),
            "\"review_required\""
        );
        assert_eq!(
            serde_json::to_string(&MemoryStatus::NoChange).unwrap(),
            "\"no_change\""
        );
    }

    #[test]
    fn wrap_up_serializes_to_snake_case_contract() {
        assert_eq!(
            serde_json::to_string(&WrapUpStatus::Clean).unwrap(),
            "\"clean\""
        );
        assert_eq!(
            serde_json::to_string(&WrapUpStatus::ReadyToCommit).unwrap(),
            "\"ready_to_commit\""
        );
        assert_eq!(
            serde_json::to_string(&WrapUpStatus::ReadyToPush).unwrap(),
            "\"ready_to_push\""
        );
        assert_eq!(
            serde_json::to_string(&WrapUpStatus::NeedsReview).unwrap(),
            "\"needs_review\""
        );
        assert_eq!(
            serde_json::to_string(&WrapUpStatus::NoChange).unwrap(),
            "\"no_change\""
        );
    }

    #[test]
    fn wrap_up_as_str_matches_serde_output() {
        for s in [
            WrapUpStatus::Clean,
            WrapUpStatus::ReadyToCommit,
            WrapUpStatus::ReadyToPush,
            WrapUpStatus::NeedsReview,
            WrapUpStatus::NoChange,
        ] {
            assert_eq!(
                serde_json::to_string(&s).unwrap(),
                format!("\"{}\"", s.as_str())
            );
        }
    }
}
