use anyhow::{Context, Result};
use std::path::PathBuf;

const LABEL: &str = "xyz.spacesh.daemon";

fn plist_path() -> Result<PathBuf> {
    let home = dirs::home_dir().context("no home")?;
    Ok(home.join("Library").join("LaunchAgents").join(format!("{LABEL}.plist")))
}

/// Render the launchd plist. `run_at_load` defaults to false in this slice.
pub fn render_plist(exe: &str, run_at_load: bool) -> String {
    format!(
        r#"<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>{LABEL}</string>
    <key>ProgramArguments</key>
    <array>
        <string>{exe}</string>
    </array>
    <key>KeepAlive</key>
    <true/>
    <key>RunAtLoad</key>
    <{run_at_load}/>
</dict>
</plist>
"#,
        run_at_load = if run_at_load { "true" } else { "false" }
    )
}

pub fn install_agent() -> Result<()> {
    let exe = std::env::current_exe()?;
    let plist = render_plist(&exe.to_string_lossy(), false);
    let path = plist_path()?;
    if let Some(parent) = path.parent() {
        std::fs::create_dir_all(parent)?;
    }
    std::fs::write(&path, plist)?;
    // Load it (best-effort; ignore "already loaded").
    let _ = std::process::Command::new("launchctl")
        .arg("load")
        .arg(&path)
        .status();
    Ok(())
}

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

    #[test]
    fn plist_has_label_keepalive_and_exe() {
        let p = render_plist("/usr/local/bin/spaceshd", false);
        assert!(p.contains("xyz.spacesh.daemon"));
        assert!(p.contains("/usr/local/bin/spaceshd"));
        assert!(p.contains("<key>KeepAlive</key>\n    <true/>"));
        assert!(p.contains("<key>RunAtLoad</key>\n    <false/>"));
    }

    #[test]
    fn run_at_load_toggles() {
        assert!(render_plist("x", true).contains("<key>RunAtLoad</key>\n    <true/>"));
    }
}
