//! Settings I/O — the ONLY place in `service/settings/` that may perform side effects.
//!
//! Side effects here include: reading/writing `.huskies/project.toml` and
//! spawning the editor process via `std::process::Command`.
//! All business logic, branching, and type definitions belong in `mod.rs`,
//! `project.rs`, or `validate.rs`.

use super::Error;
use std::path::Path;

/// Read the raw TOML content from `config_path`.
///
/// Returns an empty string if the file does not exist yet, so callers can
/// treat a missing config the same as an empty one.
///
/// # Errors
/// - [`Error::Io`] if the file exists but cannot be read.
pub(super) fn read_config_toml(config_path: &Path) -> Result<String, Error> {
    if config_path.exists() {
        std::fs::read_to_string(config_path).map_err(|e| Error::Io(format!("Read config: {e}")))
    } else {
        Ok(String::new())
    }
}

/// Write `content` to `config_path`, creating parent directories as needed.
///
/// # Errors
/// - [`Error::Io`] if the directory cannot be created or the file write fails.
pub(super) fn write_config_toml(config_path: &Path, content: &str) -> Result<(), Error> {
    if let Some(parent) = config_path.parent() {
        std::fs::create_dir_all(parent)
            .map_err(|e| Error::Io(format!("Create .huskies dir: {e}")))?;
    }
    std::fs::write(config_path, content).map_err(|e| Error::Io(format!("Write config: {e}")))
}

/// Spawn the editor process with `file_ref` as the sole argument.
///
/// Does not wait for the editor to exit — fire-and-forget so the UI remains
/// responsive.
///
/// # Errors
/// - [`Error::SpawnError`] if the operating system cannot start the process
///   (e.g. the editor binary is not on `$PATH`).
pub(super) fn spawn_editor(editor_command: &str, file_ref: &str) -> Result<(), Error> {
    std::process::Command::new(editor_command)
        .arg(file_ref)
        .spawn()
        .map(|_| ())
        .map_err(|e| Error::Spawn(format!("Failed to open editor: {e}")))
}
