use std::io;

/// Global process group manager — one per application lifetime.
///
/// On Windows, owns a Job Object with KILL_ON_JOB_CLOSE.
/// On Linux, configures the process as a child subreaper.
/// On macOS, no-op (process groups handle cleanup).
pub trait ProcessGroupManager: Send + Sync {
    /// Initialize platform-specific parent process configuration.
    fn init(&self) -> Result<(), io::Error>;

    /// Create a lifecycle handle for managing a child process.
    fn create_lifecycle(&self) -> Box<dyn ProcessLifecycle>;
}

/// Per-child process lifecycle manager.
///
/// All methods are synchronous — OS signal/handle calls are instant.
/// For timeout-based shutdown, use the free functions in the `shutdown` module.
pub trait ProcessLifecycle: Send + Sync {
    /// Configure a std::process::Command before spawning.
    /// Sets platform-specific flags (process group, creation flags, pre_exec hooks).
    fn configure_command(&self, cmd: &mut std::process::Command);

    /// Configure a tokio::process::Command before spawning.
    #[cfg(feature = "tokio")]
    fn configure_async_command(&self, cmd: &mut tokio::process::Command);

    /// Register a spawned child with the lifecycle manager.
    /// Must be called immediately after spawn with the child's PID.
    fn register_child(&self, pid: u32) -> Result<(), io::Error>;

    /// Send a graceful shutdown signal to the process (and its tree).
    /// Windows: CTRL_BREAK_EVENT. Unix: SIGTERM to process group.
    fn send_shutdown_signal(&self, pid: u32) -> Result<(), io::Error>;

    /// Forcefully kill the process (and its tree).
    /// Windows: TerminateProcess. Unix: SIGKILL to process group.
    fn send_kill_signal(&self, pid: u32) -> Result<(), io::Error>;
}
