use crate::colors::get_colors;
use crate::config::get_config;
use crate::load_data::{load_data_json, load_data_json_nested};
use crate::options::Options;
use crate::utils::{get_installed_packages, prepare_packages};

/// Searches the repository index for packages whose names contain any of the
/// given strings, and marks already-installed packages.
///
/// If `--maintainer` is given, searches by exact maintainer name instead.
/// If `--category` is given, lists all packages grouped by category name.
pub fn search(packages: &[String], options: &Options) {
    if options.maintainer {
        maintainer(packages);
        return;
    }

    if options.category {
        category(packages);
        return;
    }

    let repo = load_data_json();
    let packages = prepare_packages(packages);
    let installed = get_installed_packages();

    let cfg = get_config();
    let color = get_colors(cfg.colors);

    println!("{}Matching package(s):{}\n", color.bold, color.reset);
    for pkg in &packages {
        for (key, pkg_data) in repo.iter().filter(|(key, _)| key.contains(pkg)) {
            if installed.contains(&pkg_data.package) {
                println!(
                    "  {} {}({}){} {}[installed]{}",
                    key, color.yellow, pkg_data.version, color.reset, color.green, color.reset
                );
            } else {
                println!(
                    "  {} {}({}){}",
                    key, color.yellow, pkg_data.version, color.reset
                );
            }
        }
    }
    println!();
}

/// Lists all packages whose maintainer field exactly matches any of the given queries.
///
/// Prints an error for each query that has no matching packages.
fn maintainer(queries: &[String]) {
    let repo = load_data_json();

    let cfg = get_config();
    let color = get_colors(cfg.colors);

    println!("{}Maintainer packages:{}\n", color.bold, color.reset);

    for query in queries {
        let results: Vec<&str> = repo
            .iter()
            .filter(|(_, data)| data.maintainer == *query)
            .map(|(prgnam, _)| prgnam.as_str())
            .collect();

        if results.is_empty() {
            eprintln!(
                "{}Error:{} no packages found for maintainer '{}'",
                color.red, color.reset, query
            );
        } else {
            for prgnam in results {
                println!("  {prgnam}");
            }
        }
    }
    println!();
}

/// Lists all packages grouped by the given category names.
///
/// Prints an error for each category that does not exist in the repository.
fn category(category: &[String]) {
    let cfg = get_config();
    let color = get_colors(cfg.colors);

    let repo_nested = load_data_json_nested();

    println!("{}Category package(s){}:\n", color.bold, color.reset);
    for cat in category {
        if let Some(pkgs) = repo_nested.get(cat) {
            println!("{}{}:{}", color.cyan, cat, color.reset);
            for prgnam in pkgs.keys() {
                println!("  {prgnam}");
            }
            println!();
        } else {
            eprintln!(
                "{}Error:{} category '{}' not found\n",
                color.red, color.reset, cat
            );
        }
    }
}
