use std::{path::PathBuf, str::FromStr};

use log::info;
use serde_json::Value;
use tower_lsp::lsp_types::{Diagnostic, Url};

use crate::{diagnostics::provide_diagnostics, server::Backend, utils::{from_uri_to_escape_path_string, open_doc_as_rope}};

/// 前端请求，发布诊断结果，仅在初始化和修改配置时触发
/// 参数为 [file_path: string]
pub async fn publish_diagnostics(
    backend: &Backend,
    arguments: Vec<Value>
) -> tower_lsp::jsonrpc::Result<Option<Value>> {
    let path_string = arguments.get(0).unwrap().as_str().unwrap();
    info!("path_string: {:?}", path_string);

    let uri = Url::from_file_path(path_string).unwrap();
    let path_string = from_uri_to_escape_path_string(&uri).unwrap();
    let pathbuf = PathBuf::from_str(&path_string).unwrap();

    // 考虑到性能，如果后端文本缓冲器内存在当前路径的 文本备份，则使用它作为 rope
    // 否则，进行 IO 后再转换
    info!("open {:?} as rope", pathbuf);
    let diagnostics_params = if let Some(source) = backend.server.db.get_source(&path_string) {
        let source_handle = source.read().unwrap();
        provide_diagnostics(uri, &source_handle.text, &backend.server)
    } else {
        // 读取文件，vscode 前端是有可能存在不存在的文件的，如果文件不存在，直接返回
        let rope = open_doc_as_rope(&pathbuf);
        if rope.is_none() {
            return Ok(None);
        }
        provide_diagnostics(uri, &rope.unwrap(), &backend.server)
    };

    backend.client.publish_diagnostics(
        diagnostics_params.uri,
        diagnostics_params.diagnostics,
        None
    ).await;

    Ok(None)
}

/// 前端请求，清除诊断结果，仅在初始化和修改配置时触发
/// 参数为 [file_path: string]
pub async fn clear_diagnostics(
    backend: &Backend,
    arguments: Vec<Value>
) -> tower_lsp::jsonrpc::Result<Option<Value>> {
    let path_string = arguments.get(0).unwrap().as_str().unwrap();
    let uri = Url::from_file_path(path_string).unwrap();

    let diagnostics = Vec::<Diagnostic>::new();
    backend.client.publish_diagnostics(uri, diagnostics, None).await;

    Ok(None)
}