clawgarden-cli 0.1.1

ClawGarden CLI - Multi-bot/multi-agent Garden management tool
//! Dependency checker for ClawGarden
//!
//! Checks for required tools (docker, docker-compose, etc.)
//! with themed visual output.

use crate::ui;
use anyhow::Result;

pub struct DependencyCheck {
    pub docker: bool,
    pub docker_compose: bool,
    pub docker_running: bool,
    pub write_access: bool,
}

impl DependencyCheck {
    pub fn check_all() -> Self {
        Self {
            docker: check_command("docker"),
            docker_compose: check_command("docker-compose") || check_command("docker"),
            docker_running: check_docker_running(),
            write_access: check_garden_dir_writeable(),
        }
    }

    pub fn is_ready(&self) -> bool {
        self.docker && self.docker_compose && self.docker_running && self.write_access
    }

    pub fn print_report(&self) {
        println!();

        let items = [
            ("docker", self.docker, "🐳", "Docker binary found"),
            (
                "docker-compose",
                self.docker_compose,
                "📦",
                "docker-compose / 'docker compose' available",
            ),
            (
                "docker daemon",
                self.docker_running,
                "⚙️ ",
                "Docker daemon is running",
            ),
            (
                "~/.garden/",
                self.write_access,
                "📁",
                "Can write to garden directory",
            ),
        ];

        for (name, passed, icon, desc) in &items {
            if *passed {
                ui::success(&format!("{icon} {name:<18} {desc}"));
            } else {
                ui::error(&format!("{icon} {name:<18} missing"));
            }
        }

        ui::divider();

        if self.is_ready() {
            println!();
            ui::success("All dependencies satisfied — your garden bed is ready!");
        } else {
            println!();
            ui::error("Some dependencies are missing.\n");
            self.print_installation_guide();
        }
    }

    fn print_installation_guide(&self) {
        let _guides: Vec<(&str, &str)> = vec![];

        if !self.docker {
            ui::hint("🐳 Install Docker:");
            println!("     macOS:   brew install --cask docker");
            println!("     Ubuntu:  curl -fsSL https://get.docker.com | sh");
            println!();
        }
        if !self.docker_compose {
            ui::hint("📦 Install Docker Compose:");
            println!("     Usually included with Docker Desktop");
            println!();
        }
        if !self.docker_running {
            ui::hint("⚙️  Start Docker daemon:");
            println!("     macOS:   Open Docker Desktop app");
            println!("     Linux:   sudo systemctl start docker");
            println!();
        }
        if !self.write_access {
            ui::hint("📁 Fix ~/.garden/ permissions:");
            println!("     mkdir -p ~/.garden");
            println!();
        }
    }
}

fn check_command(cmd: &str) -> bool {
    std::process::Command::new(cmd)
        .arg("--version")
        .output()
        .is_ok()
}

fn check_docker_running() -> bool {
    std::process::Command::new("docker")
        .args(["info"])
        .output()
        .map(|o| o.status.success())
        .unwrap_or(false)
}

fn check_garden_dir_writeable() -> bool {
    let garden_dir = dirs::home_dir()
        .map(|h| h.join(".garden"))
        .unwrap_or_else(|| std::path::PathBuf::from(".garden"));

    if !garden_dir.exists() {
        std::fs::create_dir_all(&garden_dir).is_ok()
    } else {
        std::fs::metadata(&garden_dir)
            .map(|m| m.permissions().readonly() == false)
            .unwrap_or(false)
    }
}

/// Run dependency check, returns Ok if all deps available
pub fn check() -> Result<()> {
    let check = DependencyCheck::check_all();
    check.print_report();

    if !check.is_ready() {
        anyhow::bail!("Missing dependencies. Please install the missing components above.");
    }

    Ok(())
}