// Bitbucket Data Center MCP server — generated by mcpify. Do not hand-edit.

use std::future::Future;
use std::pin::Pin;
use std::sync::Mutex;

pub type CleanupFn = Box<dyn Fn() -> Pin<Box<dyn Future<Output = ()> + Send>> + Send + Sync>;

static CLEANUP_FNS: Mutex<Vec<CleanupFn>> = Mutex::new(Vec::new());

/// Registers a cleanup callback, run in reverse registration order during
/// shutdown.
pub fn on_shutdown(f: CleanupFn) {
    CLEANUP_FNS.lock().unwrap().push(f);
}

async fn shutdown(signal: &str) {
    tracing::info!(signal, "shutting down");

    let fns: Vec<CleanupFn> = {
        let mut guard = CLEANUP_FNS.lock().unwrap();
        std::mem::take(&mut *guard)
    };
    for f in fns.into_iter().rev() {
        f().await;
    }

    std::process::exit(0);
}

/// Installs SIGINT/SIGTERM handlers for graceful termination — REQ-2.3.4.
/// Spawns its own task; callers don't await this.
pub fn install_shutdown_handlers() {
    tokio::spawn(async {
        #[cfg(unix)]
        {
            let mut terminate =
                tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())
                    .expect("failed to install SIGTERM handler");
            tokio::select! {
                _ = tokio::signal::ctrl_c() => shutdown("SIGINT").await,
                _ = terminate.recv() => shutdown("SIGTERM").await,
            }
        }
        #[cfg(not(unix))]
        {
            let _ = tokio::signal::ctrl_c().await;
            shutdown("SIGINT").await;
        }
    });
}

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

    #[test]
    fn registers_a_cleanup_callback_without_panicking() {
        // `shutdown()` itself calls `std::process::exit`, so it's
        // deliberately not exercised here — same untested-by-design
        // boundary `targets::typescript`'s `shutdown-handler.ts` has.
        on_shutdown(Box::new(|| Box::pin(async {})));
    }
}
