use crate::config::Settings;
use crate::env;
use crate::error::{CjvError, Result};
use crate::resolve;
use crate::toolchain::Toolchain;
use std::process::Command;

/// Known proxy tools that cjv can proxy
pub const PROXY_TOOLS: &[&str] = &[
    "cjc",
    "cjc-frontend",
    "cjpm",
    "cjfmt",
    "cjlint",
    "cjdb",
    "cjcov",
    "cjprof",
];

/// Check if a tool name is a proxy tool
pub fn is_proxy_tool(name: &str) -> bool {
    let name = std::path::Path::new(name)
        .file_stem()
        .map(|s| s.to_string_lossy())
        .unwrap_or(std::borrow::Cow::Borrowed(name));

    PROXY_TOOLS.contains(&name.as_ref())
}

/// Extract the tool name from the binary path
pub fn extract_tool_name(arg0: &str) -> String {
    std::path::Path::new(arg0)
        .file_stem()
        .map(|s| s.to_string_lossy().to_string())
        .unwrap_or_else(|| arg0.to_string())
}

/// Run a proxied tool
pub fn run_proxy(tool_name: &str, args: &[String]) -> Result<i32> {
    // Resolve the active toolchain
    let settings = Settings::load()?;
    let active_tc = crate::config::resolve_active_toolchain(&settings)
        .ok_or_else(|| {
            CjvError::Other(
                "No active toolchain configured. Install one with 'cjv install lts' and set it as default with 'cjv default lts'".to_string(),
            )
        })?;

    // Check if toolchain is installed, auto-install if enabled
    if !Toolchain::is_installed(&active_tc) {
        if settings.get_auto_install() {
            println!(
                "Toolchain '{}' is not installed. Installing automatically...",
                active_tc
            );
            // Perform auto-install synchronously using a simple async block
            let rt = tokio::runtime::Runtime::new()
                .map_err(|e| CjvError::Other(format!("Failed to create runtime: {}", e)))?;
            rt.block_on(auto_install_toolchain(&active_tc, &settings))?;
        } else {
            return Err(CjvError::ToolchainNotInstalled(active_tc));
        }
    }

    // Find the actual tool binary
    let tool_path = resolve::find_tool_path(&active_tc, tool_name)?;

    // Build the runtime environment
    let mut cmd = Command::new(&tool_path);
    cmd.args(args);
    env::inject_runtime_env(&mut cmd, &active_tc);

    // Inherit stdio and run
    let mut child = cmd
        .stdin(std::process::Stdio::inherit())
        .stdout(std::process::Stdio::inherit())
        .stderr(std::process::Stdio::inherit())
        .spawn()
        .map_err(|e| {
            CjvError::Proxy(format!(
                "Failed to execute '{}': {}",
                tool_path.display(),
                e
            ))
        })?;

    let status = child
        .wait()
        .map_err(|e| CjvError::Proxy(format!("Failed to wait for '{}': {}", tool_name, e)))?;

    Ok(status.code().unwrap_or(1))
}

/// Auto-install a missing toolchain during proxy execution
async fn auto_install_toolchain(name: &str, settings: &Settings) -> Result<()> {
    let tc_name = crate::dist::download_and_install_toolchain(name, settings).await?;
    println!("Toolchain '{}' installed automatically.", tc_name);
    Ok(())
}