mod config;
mod event_log;
mod event_store;
mod hooks;
mod launchd;
mod lifecycle;
mod persist;
mod registry;
mod server;
mod snapshot_store;
mod state_store;
mod surface;

use anyhow::Result;

/// Test-only support shared across the crate's test modules.
#[cfg(test)]
pub(crate) mod test_support {
    use std::sync::{Mutex, MutexGuard};

    /// Process-wide serialization lock for the heavy socket/PTY integration tests.
    /// These bind sockets and spawn real PTYs/processes; running several at once on a
    /// many-core box starves each other's tasks and trips timing assumptions. Unit
    /// tests stay parallel; only guarded integration tests serialize on this lock.
    static SERIAL: Mutex<()> = Mutex::new(());

    /// Acquire the serial lock for the duration of a test. Poison-tolerant so one
    /// panicking test does not cascade-fail the rest.
    pub(crate) fn serial() -> MutexGuard<'static, ()> {
        SERIAL.lock().unwrap_or_else(|e| e.into_inner())
    }
}

#[tokio::main]
async fn main() -> Result<()> {
    let arg = std::env::args().nth(1);
    match arg.as_deref() {
        Some("install-agent") => {
            launchd::install_agent()?;
            println!("launchd agent installed");
            Ok(())
        }
        Some("--help") | Some("-h") => {
            println!("spaceshd [install-agent]");
            Ok(())
        }
        _ => run_daemon().await,
    }
}

async fn run_daemon() -> Result<()> {
    let Some(_lock) = lifecycle::acquire_instance_lock()? else {
        eprintln!("another spaceshd is already running");
        return Ok(());
    };
    lifecycle::clear_stale_socket()?;
    let sock = lifecycle::socket_path()?;
    let state_path = lifecycle::spacesh_dir()?.join("state.json");
    let store: std::sync::Arc<dyn state_store::StateStore> =
        std::sync::Arc::new(state_store::JsonStateStore::new(state_path));
    let events_path = lifecycle::spacesh_dir()?.join("events.json");
    let event_store: std::sync::Arc<dyn event_store::EventStore> =
        std::sync::Arc::new(event_store::JsonEventStore::new(events_path));
    let snapshots_dir = lifecycle::spacesh_dir()?.join("snapshots");
    let snapshot_store: std::sync::Arc<dyn snapshot_store::SnapshotStore> =
        std::sync::Arc::new(snapshot_store::JsonSnapshotStore::new(snapshots_dir));
    eprintln!("spaceshd listening on {}", sock.display());
    server::serve(&sock, store, event_store, snapshot_store).await
}
