use std::path::Path;
use std::process::Command;

use crate::plugin::{CleanAction, CleanTarget, Plugin, Safety};
use crate::utils;

pub struct GoPlugin;

impl Plugin for GoPlugin {
    fn name(&self) -> &str {
        "go"
    }

    fn description(&self) -> &str {
        "Go build cache, module cache, and gopls data"
    }

    fn scan_directory(&self, _dir: &Path) -> Vec<CleanTarget> {
        Vec::new()
    }

    fn global_targets(&self) -> Vec<CleanTarget> {
        let mut targets = Vec::new();
        let home = utils::home_dir();

        // go build cache
        let build_cache = go_cache_dir();
        if build_cache.is_dir() {
            let size = utils::dir_size(&build_cache);
            targets.push(CleanTarget {
                label: format!("{}", build_cache.display()),
                size_bytes: size,
                action: CleanAction::RunCommand {
                    command: "go".to_string(),
                    args: vec!["clean".to_string(), "-cache".to_string()],
                    description: "go clean -cache".to_string(),
                },
                plugin_name: self.name().to_string(),
                safety: Safety::Recoverable,
                explanation: "Go build cache, regenerated on next build".to_string(),
            });
        }

        // go module cache
        let mod_cache = home.join("go/pkg/mod");
        if mod_cache.is_dir() {
            let size = utils::dir_size(&mod_cache);
            targets.push(CleanTarget {
                label: format!("{}", mod_cache.display()),
                size_bytes: size,
                action: CleanAction::RunCommand {
                    command: "go".to_string(),
                    args: vec!["clean".to_string(), "-modcache".to_string()],
                    description: "go clean -modcache".to_string(),
                },
                plugin_name: self.name().to_string(),
                safety: Safety::Recoverable,
                explanation: "Go module cache, re-downloaded as needed".to_string(),
            });
        }

        // gopls cache
        let gopls_cache = gopls_cache_dir();
        if gopls_cache.is_dir() {
            let size = utils::dir_size(&gopls_cache);
            targets.push(CleanTarget {
                label: format!("{}", gopls_cache.display()),
                size_bytes: size,
                action: CleanAction::DeletePath(gopls_cache),
                plugin_name: self.name().to_string(),
                safety: Safety::Recoverable,
                explanation: "Go language server cache, regenerated automatically".to_string(),
            });
        }

        targets
    }

    fn is_available(&self) -> bool {
        Command::new("go")
            .arg("version")
            .stdout(std::process::Stdio::null())
            .stderr(std::process::Stdio::null())
            .status()
            .map(|s| s.success())
            .unwrap_or(false)
    }
}

fn go_cache_dir() -> std::path::PathBuf {
    if cfg!(target_os = "macos") {
        utils::home_dir().join("Library/Caches/go-build")
    } else {
        utils::home_dir().join(".cache/go-build")
    }
}

fn gopls_cache_dir() -> std::path::PathBuf {
    if cfg!(target_os = "macos") {
        utils::home_dir().join("Library/Caches/gopls")
    } else {
        utils::home_dir().join(".cache/gopls")
    }
}
