//! Session state — global mutable state shared across the server (project root, cancellation).
use std::path::PathBuf;
use std::sync::Mutex;
use tokio::sync::watch;

/// Global server session state: the open project root and a cancellation signal.
pub struct SessionState {
    pub project_root: Mutex<Option<PathBuf>>,
    pub cancel_tx: watch::Sender<bool>,
    pub cancel_rx: watch::Receiver<bool>,
}

impl Default for SessionState {
    fn default() -> Self {
        let (cancel_tx, cancel_rx) = watch::channel(false);
        Self {
            project_root: Mutex::new(None),
            cancel_tx,
            cancel_rx,
        }
    }
}

impl SessionState {
    /// Return the currently open project root, or an error if no project is open.
    pub fn get_project_root(&self) -> Result<PathBuf, String> {
        let root_guard = self.project_root.lock().map_err(|e| e.to_string())?;
        let root = root_guard.as_ref().ok_or_else(|| {
            // TRACE:MERGE-DEBUG — remove once root cause is found
            crate::slog_error!(
                "[MERGE-DEBUG] get_project_root() called but project_root is None! \
                 Backtrace hint: check caller in MCP tool handler."
            );
            "No project is currently open.".to_string()
        })?;
        Ok(root.clone())
    }
}
