use std::sync::Arc;
use std::future;
use log::info;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use tower_lsp::jsonrpc::Result;

use crate::{diagnostics::update_diagnostics_configuration, server::Backend};

#[derive(Clone)]
pub struct UpdateConfigurationApi;

#[derive(Deserialize, Serialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct UpdateConfigurationParams {
    configs: Vec<UpdateConfigurationItem>,
    config_type: String
}

#[derive(Deserialize, Serialize, Debug)]
#[serde(rename_all = "camelCase")]
struct UpdateConfigurationItem {
    name: String,
    value: Value
}

impl <'a>tower_lsp::jsonrpc::Method<&'a Arc<Backend>, (UpdateConfigurationParams, ), Result<()>> for UpdateConfigurationApi {
    type Future = future::Ready<Result<()>>;

    fn invoke(&self, _server: &'a Arc<Backend>, _params: (UpdateConfigurationParams, )) -> Self::Future {        
        let request_param = _params.0;
        let configs = request_param.configs;
        
        // 用于未来进行配置分区
        let config_type = request_param.config_type;
        
        update_configuration(configs, config_type, &_server);
        future::ready(Ok(()))
    }
}

/// 前端配置文件的更新
fn update_configuration(
    configs: Vec<UpdateConfigurationItem>,
    config_type: String,
    backend: &Arc<Backend>
) {
    let mut lsp_configuration = backend.server.srcs.lsp_configuration.write().unwrap();
    
    match config_type.as_str() {
        // 所有配置同步到 lsp_configuration 中
        "lsp" => {
            for config in configs {
                info!("update config, name: {}, value: {}", config.name, config.value);
                lsp_configuration.insert(config.name, config.value);
            }
        },

        // 针对当前项目选择的诊断器的更新
        // 此时 configs 的长度必然为 2
        // configs.0 含有当前选择的诊断器的名字的信息，比如 "digital-ide.function.lsp.linter.vlog.diagnostor": "vivado"
        // configs.1 含有第三方诊断器的合法路径相关的信息，比如 "path": "/opt/xilinx/Vivado/2022.2/bin/xvlog"
        "linter" => {
            if configs.len() < 2 {
                info!("update_configuration, type : {}, 发生错误，原因：configs 数量不为 2", config_type);
                return;
            }
            
            let linter_name_configuration = &configs[0];
            let linter_path_configuration = &configs[1];

            // linter_name_config_name 形如 digital-ide.function.lsp.linter.vlog.diagnostor
            let linter_name_config_name = &linter_name_configuration.name;

            // 同步到全局配置中
            lsp_configuration.insert(
                linter_name_config_name.to_string(), 
                linter_name_configuration.value.clone()
            );

            // 从 linter_name_configuration.name 解析出 language_id
            let language_id = {
                // linter_name_config_name 形如 digital-ide.function.lsp.linter.vlog.diagnostor
                let mut cookies = linter_name_config_name.split(".");
                let name = cookies.nth(4).unwrap();
                name
            };
            
            let linter_name = linter_name_configuration.value.as_str().unwrap();
            let linter_path = linter_path_configuration.value.as_str().unwrap();

            update_diagnostics_configuration(
                &backend.server,
                linter_name,
                language_id,
                linter_path
            );
        },

        _ => {}
    }
}