use tombi_text::IntoLsp;
use tower_lsp::lsp_types::TextDocumentPositionParams;
use tower_lsp::lsp_types::request::GotoDeclarationParams;

use crate::Backend;
use crate::config_manager::ConfigSchemaStore;
use crate::handler::hover::get_hover_keys_with_range;

pub async fn handle_goto_declaration(
    backend: &Backend,
    params: GotoDeclarationParams,
) -> Result<Option<Vec<tombi_extension::DefinitionLocation>>, tower_lsp::jsonrpc::Error> {
    log::info!("handle_goto_declaration");
    log::trace!("{:?}", params);

    let GotoDeclarationParams {
        text_document_position_params:
            TextDocumentPositionParams {
                text_document,
                position,
            },
        ..
    } = params;
    let text_document_uri = text_document.uri.into();

    let ConfigSchemaStore { config, .. } = backend
        .config_manager
        .config_schema_store_for_uri(&text_document_uri)
        .await;

    if !config
        .lsp
        .as_ref()
        .and_then(|server| server.goto_declaration.as_ref())
        .and_then(|goto_declaration| goto_declaration.enabled)
        .unwrap_or_default()
        .value()
    {
        log::debug!("`server.goto_declaration.enabled` is false");
        return Ok(None);
    }

    let document_sources = backend.document_sources.read().await;
    let Some(document_source) = document_sources.get(&text_document_uri) else {
        return Ok(None);
    };

    let root = document_source.ast();
    let toml_version = document_source.toml_version;
    let line_index = document_source.line_index();

    let position = position.into_lsp(line_index);

    let Some((keys, _)) = get_hover_keys_with_range(&root, position, toml_version).await else {
        return Ok(None);
    };

    let document_tree = document_source.document_tree();
    let accessors = tombi_document_tree::get_accessors(&document_tree, &keys, position);

    if let Some(locations) = tombi_extension_cargo::goto_declaration(
        &text_document_uri,
        &document_tree,
        &accessors,
        toml_version,
    )
    .await?
    {
        return Ok(locations.into());
    }

    if let Some(locations) = tombi_extension_uv::goto_declaration(
        &text_document_uri,
        &document_tree,
        &accessors,
        toml_version,
    )
    .await?
    {
        return Ok(locations.into());
    }

    Ok(None)
}
