use std::sync::Arc;

use lsp_types::GotoDefinitionParams;
use rowan::ast::AstNode;

use crate::{
    features::cursor::CursorContext,
    syntax::bibtex::{self, HasName},
};

use super::DefinitionResult;

pub(super) fn goto_string_definition(
    context: &CursorContext<GotoDefinitionParams>,
) -> Option<Vec<DefinitionResult>> {
    let main_document = context.request.main_document();

    let data = main_document.data.as_bibtex()?;
    let key = context
        .cursor
        .as_bibtex()
        .filter(|token| token.kind() == bibtex::NAME)?;

    bibtex::Value::cast(key.parent()?)?;

    let origin_selection_range = key.text_range();

    for string in bibtex::SyntaxNode::new_root(data.green.clone())
        .children()
        .filter_map(bibtex::StringDef::cast)
    {
        if let Some(string_name) = string.name_token().filter(|k| k.text() == key.text()) {
            return Some(vec![DefinitionResult {
                origin_selection_range,
                target_uri: Arc::clone(&main_document.uri),
                target_selection_range: string_name.text_range(),
                target_range: string.syntax().text_range(),
            }]);
        }
    }

    None
}
