use anyhow::{bail, Result};

use crate::registry::{packages, tools, Scope};
use crate::ui::style;

pub fn run(name: &str) -> Result<()> {
    if let Some(r) = tools::resolve(name)? {
        print_tool(&r);
        return Ok(());
    }
    if let Some(r) = packages::resolve(name)? {
        print_package(&r);
        return Ok(());
    }
    bail!(
        "no tool or package named `{name}` in the registry — try `aimgr registry` to list what's available"
    );
}

fn print_tool(r: &tools::Resolved) {
    let t = &r.tool;
    println!(
        "{}  {}",
        style::bold(&t.name),
        style::dim(format!("({})", r.source.label()))
    );
    kv("kind", "tool");
    if let Some(runtime) = t.runtime {
        kv("runtime", runtime.as_str());
    }
    if let Some(d) = &t.description {
        kv("description", d);
    }
    if let Some(h) = &t.homepage {
        kv("homepage", h);
    }
    print_install_methods(&t.install);
    if t.update.is_some() {
        kv("update", "supported");
    }
    if t.uninstall.is_some() {
        kv("uninstall", "supported");
    }
}

fn print_package(r: &packages::Resolved) {
    let p = &r.package;
    println!(
        "{}  {}",
        style::bold(&p.name),
        style::dim(format!("({})", r.source.label()))
    );
    kv("kind", "package");
    kv("scope", scope_label(p.scope));
    let tools_list: Vec<&str> = p.tools.iter().map(|t| t.as_str()).collect();
    let applies_to = if tools_list.is_empty() {
        "any active tool".to_string()
    } else {
        tools_list.join(", ")
    };
    kv("applies to", &applies_to);
    if let Some(d) = &p.description {
        kv("description", d);
    }
    if let Some(h) = &p.homepage {
        kv("homepage", h);
    }
    if !p.depends_on.is_empty() {
        kv("depends on", &p.depends_on.join(", "));
    }
    print_install_methods(&p.install);
    if p.update.is_some() {
        kv("update", "supported");
    }
    if p.uninstall.is_some() {
        kv("uninstall", "supported");
    }
    if !p.instructions.is_empty() {
        kv(
            "instructions",
            &format!("{} block(s)", p.instructions.len()),
        );
    }
}

fn kv(label: &str, value: &str) {
    println!("  {} {value}", style::dim(format!("{label}:")));
}

fn print_install_methods(install: &[crate::registry::InstallMethod]) {
    if install.is_empty() {
        return;
    }
    println!("  {}", style::dim("install methods:"));
    for m in install {
        let label = m.label.as_deref().unwrap_or(&m.id);
        println!("    - {} {}", m.id, style::dim(format!("({label})")));
    }
}

fn scope_label(s: Scope) -> &'static str {
    match s {
        Scope::Global => "global",
        Scope::Project => "project",
        Scope::Both => "both",
    }
}
