//! Random assortment of ide helpers for high-level ide features that don't fit in any other module.

use std::collections::VecDeque;

use base_db::SourceDatabase;
use hir::{Crate, ItemInNs, ModuleDef, Name, Semantics};
use span::{Edition, FileId};
use syntax::{
    AstToken, SyntaxKind, SyntaxToken, ToSmolStr, TokenAtOffset,
    ast::{self, make},
};

use crate::{
    RootDatabase,
    defs::{Definition, IdentClass},
    generated,
};

pub fn item_name(db: &RootDatabase, item: ItemInNs) -> Option<Name> {
    match item {
        ItemInNs::Types(module_def_id) => module_def_id.name(db),
        ItemInNs::Values(module_def_id) => module_def_id.name(db),
        ItemInNs::Macros(macro_def_id) => Some(macro_def_id.name(db)),
    }
}

/// Picks the token with the highest rank returned by the passed in function.
pub fn pick_best_token(
    tokens: TokenAtOffset<SyntaxToken>,
    f: impl Fn(SyntaxKind) -> usize,
) -> Option<SyntaxToken> {
    tokens.max_by_key(move |t| f(t.kind()))
}
pub fn pick_token<T: AstToken>(mut tokens: TokenAtOffset<SyntaxToken>) -> Option<T> {
    tokens.find_map(T::cast)
}

/// Converts the mod path struct into its ast representation.
pub fn mod_path_to_ast(path: &hir::ModPath, edition: Edition) -> ast::Path {
    let _p = tracing::info_span!("mod_path_to_ast").entered();

    let mut segments = Vec::new();
    let mut is_abs = false;
    match path.kind {
        hir::PathKind::Plain => {}
        hir::PathKind::SELF => segments.push(make::path_segment_self()),
        hir::PathKind::Super(n) => segments.extend((0..n).map(|_| make::path_segment_super())),
        hir::PathKind::DollarCrate(_) | hir::PathKind::Crate => {
            segments.push(make::path_segment_crate())
        }
        hir::PathKind::Abs => is_abs = true,
    }

    segments.extend(path.segments().iter().map(|segment| {
        make::path_segment(make::name_ref(&segment.display_no_db(edition).to_smolstr()))
    }));
    make::path_from_segments(segments, is_abs)
}

/// Iterates all `ModuleDef`s and `Impl` blocks of the given file.
pub fn visit_file_defs(
    sema: &Semantics<'_, RootDatabase>,
    file_id: FileId,
    cb: &mut dyn FnMut(Definition),
) {
    let db = sema.db;
    let module = match sema.file_to_module_def(file_id) {
        Some(it) => it,
        None => return,
    };
    let mut defs: VecDeque<_> = module.declarations(db).into();
    while let Some(def) = defs.pop_front() {
        if let ModuleDef::Module(submodule) = def
            && submodule.is_inline(db)
        {
            defs.extend(submodule.declarations(db));
            submodule.impl_defs(db).into_iter().for_each(|impl_| cb(impl_.into()));
        }
        cb(def.into());
    }
    module.impl_defs(db).into_iter().for_each(|impl_| cb(impl_.into()));

    let is_root = module.is_crate_root();
    module
        .legacy_macros(db)
        .into_iter()
        // don't show legacy macros declared in the crate-root that were already covered in declarations earlier
        .filter(|it| !(is_root && it.is_macro_export(db)))
        .for_each(|mac| cb(mac.into()));
}

/// Checks if the given lint is equal or is contained by the other lint which may or may not be a group.
pub fn lint_eq_or_in_group(lint: &str, lint_is: &str) -> bool {
    if lint == lint_is {
        return true;
    }

    if let Some(group) = generated::lints::DEFAULT_LINT_GROUPS
        .iter()
        .chain(generated::lints::CLIPPY_LINT_GROUPS.iter())
        .chain(generated::lints::RUSTDOC_LINT_GROUPS.iter())
        .find(|&check| check.lint.label == lint_is)
    {
        group.children.contains(&lint)
    } else {
        false
    }
}

pub fn is_editable_crate(krate: Crate, db: &RootDatabase) -> bool {
    let root_file = krate.root_file(db);
    let source_root_id = db.file_source_root(root_file).source_root_id(db);
    !db.source_root(source_root_id).source_root(db).is_library
}

// FIXME: This is a weird function
pub fn get_definition(
    sema: &Semantics<'_, RootDatabase>,
    token: SyntaxToken,
) -> Option<Definition> {
    for token in sema.descend_into_macros_exact(token) {
        let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops);
        if let Some(&[x]) = def.as_deref() {
            return Some(x);
        }
    }
    None
}
