use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};

/// A cooperative cancellation token for graceful shutdown.
///
/// Clone-able and cheaply checkable from any thread or async task.
/// When `cancel()` is called (typically from a Ctrl+C signal handler),
/// all clones observe the cancellation via `is_cancelled()`.
#[derive(Clone)]
pub struct ShutdownSignal {
    cancelled: Arc<AtomicBool>,
}

impl ShutdownSignal {
    pub fn new() -> Self {
        Self {
            cancelled: Arc::new(AtomicBool::new(false)),
        }
    }

    pub fn cancel(&self) {
        self.cancelled.store(true, Ordering::Release);
    }

    pub fn is_cancelled(&self) -> bool {
        self.cancelled.load(Ordering::Acquire)
    }
}

impl Default for ShutdownSignal {
    fn default() -> Self {
        Self::new()
    }
}

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

    #[test]
    fn signal_starts_uncancelled() {
        let signal = ShutdownSignal::new();
        assert!(!signal.is_cancelled());
    }

    #[test]
    fn cancel_sets_flag() {
        let signal = ShutdownSignal::new();
        signal.cancel();
        assert!(signal.is_cancelled());
    }

    #[test]
    fn clone_propagates_cancellation() {
        let signal = ShutdownSignal::new();
        let clone = signal.clone();
        signal.cancel();
        assert!(
            clone.is_cancelled(),
            "clone should see cancellation from original"
        );
    }
}
