//! Searching for matches.

use crate::{
    Match, MatchFinder, matching,
    resolving::{ResolvedPath, ResolvedPattern, ResolvedRule},
};
use hir::FileRange;
use ide_db::{
    EditionedFileId, FileId, FxHashSet,
    defs::Definition,
    search::{SearchScope, UsageSearchResult},
};
use syntax::{AstNode, SyntaxKind, SyntaxNode, ast};

/// A cache for the results of find_usages. This is for when we have multiple patterns that have the
/// same path. e.g. if the pattern was `foo::Bar` that can parse as a path, an expression, a type
/// and as a pattern. In each, the usages of `foo::Bar` are the same and we'd like to avoid finding
/// them more than once.
#[derive(Default)]
pub(crate) struct UsageCache {
    usages: Vec<(Definition, UsageSearchResult)>,
}

impl<'db> MatchFinder<'db> {
    /// Adds all matches for `rule` to `matches_out`. Matches may overlap in ways that make
    /// replacement impossible, so further processing is required in order to properly nest matches
    /// and remove overlapping matches. This is done in the `nesting` module.
    pub(crate) fn find_matches_for_rule(
        &self,
        rule: &ResolvedRule<'db>,
        usage_cache: &mut UsageCache,
        matches_out: &mut Vec<Match>,
    ) {
        if rule.pattern.contains_self {
            // If the pattern contains `self` we restrict the scope of the search to just the
            // current method. No other method can reference the same `self`. This makes the
            // behavior of `self` consistent with other variables.
            if let Some(current_function) = self.resolution_scope.current_function() {
                self.slow_scan_node(&current_function, rule, &None, matches_out);
            }
            return;
        }
        if pick_path_for_usages(&rule.pattern).is_none() {
            self.slow_scan(rule, matches_out);
            return;
        }
        self.find_matches_for_pattern_tree(rule, &rule.pattern, usage_cache, matches_out);
    }

    fn find_matches_for_pattern_tree(
        &self,
        rule: &ResolvedRule<'db>,
        pattern: &ResolvedPattern<'db>,
        usage_cache: &mut UsageCache,
        matches_out: &mut Vec<Match>,
    ) {
        if let Some(resolved_path) = pick_path_for_usages(pattern) {
            let definition: Definition = resolved_path.resolution.into();
            for file_range in self.find_usages(usage_cache, definition).file_ranges() {
                for node_to_match in self.find_nodes_to_match(resolved_path, file_range) {
                    if !is_search_permitted_ancestors(&node_to_match) {
                        cov_mark::hit!(use_declaration_with_braces);
                        continue;
                    }
                    self.try_add_match(rule, &node_to_match, &None, matches_out);
                }
            }
        }
    }

    fn find_nodes_to_match(
        &self,
        resolved_path: &ResolvedPath,
        file_range: FileRange,
    ) -> Vec<SyntaxNode> {
        let file = self.sema.parse(file_range.file_id);
        let depth = resolved_path.depth as usize;
        let offset = file_range.range.start();

        let mut paths = self
            .sema
            .find_nodes_at_offset_with_descend::<ast::Path>(file.syntax(), offset)
            .peekable();

        if paths.peek().is_some() {
            paths
                .filter_map(|path| {
                    self.sema.ancestors_with_macros(path.syntax().clone()).nth(depth)
                })
                .collect::<Vec<_>>()
        } else {
            self.sema
                .find_nodes_at_offset_with_descend::<ast::MethodCallExpr>(file.syntax(), offset)
                .filter_map(|path| {
                    // If the pattern contained a path and we found a reference to that path that wasn't
                    // itself a path, but was a method call, then we need to adjust how far up to try
                    // matching by how deep the path was within a CallExpr. The structure would have been
                    // CallExpr, PathExpr, Path - i.e. a depth offset of 2. We don't need to check if the
                    // path was part of a CallExpr because if it wasn't then all that will happen is we'll
                    // fail to match, which is the desired behavior.
                    const PATH_DEPTH_IN_CALL_EXPR: usize = 2;
                    if depth < PATH_DEPTH_IN_CALL_EXPR {
                        return None;
                    }
                    self.sema
                        .ancestors_with_macros(path.syntax().clone())
                        .nth(depth - PATH_DEPTH_IN_CALL_EXPR)
                })
                .collect::<Vec<_>>()
        }
    }

    fn find_usages<'a>(
        &self,
        usage_cache: &'a mut UsageCache,
        definition: Definition,
    ) -> &'a UsageSearchResult {
        // Logically if a lookup succeeds we should just return it. Unfortunately returning it would
        // extend the lifetime of the borrow, then we wouldn't be able to do the insertion on a
        // cache miss. This is a limitation of NLL and is fixed with Polonius. For now we do two
        // lookups in the case of a cache hit.
        if usage_cache.find(&definition).is_none() {
            let usages = definition.usages(&self.sema).in_scope(&self.search_scope()).all();
            usage_cache.usages.push((definition, usages));
            return &usage_cache.usages.last().unwrap().1;
        }
        usage_cache.find(&definition).unwrap()
    }

    /// Returns the scope within which we want to search. We don't want un unrestricted search
    /// scope, since we don't want to find references in external dependencies.
    fn search_scope(&self) -> SearchScope {
        // FIXME: We should ideally have a test that checks that we edit local roots and not library
        // roots. This probably would require some changes to fixtures, since currently everything
        // seems to get put into a single source root.
        let mut files = Vec::new();
        self.search_files_do(|file_id| {
            files.push(
                self.sema
                    .attach_first_edition(file_id)
                    .unwrap_or_else(|| EditionedFileId::current_edition(self.sema.db, file_id)),
            );
        });
        SearchScope::files(&files)
    }

    fn slow_scan(&self, rule: &ResolvedRule<'db>, matches_out: &mut Vec<Match>) {
        self.search_files_do(|file_id| {
            let file = self.sema.parse_guess_edition(file_id);
            let code = file.syntax();
            self.slow_scan_node(code, rule, &None, matches_out);
        })
    }

    fn search_files_do(&self, mut callback: impl FnMut(FileId)) {
        if self.restrict_ranges.is_empty() {
            // Unrestricted search.
            use ide_db::base_db::SourceDatabase;
            use ide_db::symbol_index::SymbolsDatabase;
            for &root in self.sema.db.local_roots().iter() {
                let sr = self.sema.db.source_root(root).source_root(self.sema.db);
                for file_id in sr.iter() {
                    callback(file_id);
                }
            }
        } else {
            // Search is restricted, deduplicate file IDs (generally only one).
            let mut files = FxHashSet::default();
            for range in &self.restrict_ranges {
                if files.insert(range.file_id) {
                    callback(range.file_id);
                }
            }
        }
    }

    fn slow_scan_node(
        &self,
        code: &SyntaxNode,
        rule: &ResolvedRule<'db>,
        restrict_range: &Option<FileRange>,
        matches_out: &mut Vec<Match>,
    ) {
        if !is_search_permitted(code) {
            return;
        }
        self.try_add_match(rule, code, restrict_range, matches_out);
        // If we've got a macro call, we already tried matching it pre-expansion, which is the only
        // way to match the whole macro, now try expanding it and matching the expansion.
        if let Some(macro_call) = ast::MacroCall::cast(code.clone())
            && let Some(expanded) = self.sema.expand_macro_call(&macro_call)
            && let Some(tt) = macro_call.token_tree()
        {
            // When matching within a macro expansion, we only want to allow matches of
            // nodes that originated entirely from within the token tree of the macro call.
            // i.e. we don't want to match something that came from the macro itself.
            if let Some(range) = self.sema.original_range_opt(tt.syntax()) {
                self.slow_scan_node(&expanded.value, rule, &Some(range), matches_out);
            }
        }
        for child in code.children() {
            self.slow_scan_node(&child, rule, restrict_range, matches_out);
        }
    }

    fn try_add_match(
        &self,
        rule: &ResolvedRule<'db>,
        code: &SyntaxNode,
        restrict_range: &Option<FileRange>,
        matches_out: &mut Vec<Match>,
    ) {
        if !self.within_range_restrictions(code) {
            cov_mark::hit!(replace_nonpath_within_selection);
            return;
        }
        if let Ok(m) = matching::get_match(false, rule, code, restrict_range, &self.sema) {
            matches_out.push(m);
        }
    }

    /// Returns whether `code` is within one of our range restrictions if we have any. No range
    /// restrictions is considered unrestricted and always returns true.
    fn within_range_restrictions(&self, code: &SyntaxNode) -> bool {
        if self.restrict_ranges.is_empty() {
            // There is no range restriction.
            return true;
        }
        let Some(node_range) = self.sema.original_range_opt(code) else { return false };
        for range in &self.restrict_ranges {
            if range.file_id == node_range.file_id.file_id(self.sema.db)
                && range.range.contains_range(node_range.range)
            {
                return true;
            }
        }
        false
    }
}

/// Returns whether we support matching within `node` and all of its ancestors.
fn is_search_permitted_ancestors(node: &SyntaxNode) -> bool {
    if let Some(parent) = node.parent()
        && !is_search_permitted_ancestors(&parent)
    {
        return false;
    }
    is_search_permitted(node)
}

/// Returns whether we support matching within this kind of node.
fn is_search_permitted(node: &SyntaxNode) -> bool {
    // FIXME: Properly handle use declarations. At the moment, if our search pattern is `foo::bar`
    // and the code is `use foo::{baz, bar}`, we'll match `bar`, since it resolves to `foo::bar`.
    // However we'll then replace just the part we matched `bar`. We probably need to instead remove
    // `bar` and insert a new use declaration.
    node.kind() != SyntaxKind::USE
}

impl UsageCache {
    fn find(&mut self, definition: &Definition) -> Option<&UsageSearchResult> {
        // We expect a very small number of cache entries (generally 1), so a linear scan should be
        // fast enough and avoids the need to implement Hash for Definition.
        for (d, refs) in &self.usages {
            if d == definition {
                return Some(refs);
            }
        }
        None
    }
}

/// Returns a path that's suitable for path resolution. We exclude builtin types, since they aren't
/// something that we can find references to. We then somewhat arbitrarily pick the path that is the
/// longest as this is hopefully more likely to be less common, making it faster to find.
fn pick_path_for_usages<'a>(pattern: &'a ResolvedPattern<'_>) -> Option<&'a ResolvedPath> {
    // FIXME: Take the scope of the resolved path into account. e.g. if there are any paths that are
    // private to the current module, then we definitely would want to pick them over say a path
    // from std. Possibly we should go further than this and intersect the search scopes for all
    // resolved paths then search only in that scope.
    pattern
        .resolved_paths
        .iter()
        .filter(|(_, p)| {
            !matches!(p.resolution, hir::PathResolution::Def(hir::ModuleDef::BuiltinType(_)))
        })
        .map(|(node, resolved)| (node.text().len(), resolved))
        .max_by(|(a, _), (b, _)| a.cmp(b))
        .map(|(_, resolved)| resolved)
}
