use crate::completion::directives::provide_vlog_directives_completions;
use crate::core::cache_storage::CacheManager;
use crate::diagnostics::DigitalLinterConfiguration;
use crate::sources::*;
use crate::completion::{keyword::*, provide_vlog_sys_tasks_completions};
use flexi_logger::LoggerHandle;
#[allow(unused)]
use log::{debug, info, warn};
use serde::{Deserialize, Serialize};
use std::string::ToString;
use std::sync::{Arc, Mutex, RwLock};
use tower_lsp::jsonrpc::Result;
use tower_lsp::lsp_types::*;
use tower_lsp::{Client, LanguageServer};
pub struct LspServer {
    /// 文件和 ast 相关的
    pub srcs: Sources,
    /// 缓存
    pub cache: CacheManager,
    /// verilog 关键词的自动补全
    pub vlog_keyword_completion_items: Vec<CompletionItem>,
    /// verilog 的系统调用的自动补全
    pub vlog_sys_tasks_completion_items: Vec<CompletionItem>,
    /// verilog 的所有宏的自动补全
    pub vlog_directives: Vec<CompletionItem>,
    /// vhdl 关键词的自动补全
    pub vhdl_keyword_completiom_items: Vec<CompletionItem>,
    /// 相关的配置项目
    pub configuration: Arc<RwLock<LspConfiguration>>,

    #[allow(unused)]
    pub log_handle: Mutex<Option<LoggerHandle>>,
}

impl LspServer {
    pub fn new(log_handle: Option<LoggerHandle>) -> LspServer {
        let user_home = dirs_next::home_dir().unwrap();
        let dide_home = user_home.join(".digital-ide");
        LspServer {
            srcs: Sources::new(),
            cache: CacheManager::new(dide_home),
            vlog_keyword_completion_items: provide_keyword_completions(VLOG_KEYWORDS),
            vhdl_keyword_completiom_items: provide_keyword_completions(VHDL_KEYWORDS),
            vlog_sys_tasks_completion_items: provide_vlog_sys_tasks_completions(),
            vlog_directives: provide_vlog_directives_completions(),
            configuration: Arc::new(RwLock::new(LspConfiguration::default())),
            log_handle: Mutex::new(log_handle),
        }
    }
}

pub struct Backend {
    pub client: Client,
    pub server: LspServer
}


impl Backend {
    pub fn new(client: Client, log_handle: LoggerHandle) -> Backend {
        Backend {
            client,
            server: LspServer::new(Some(log_handle)),
        }
    }
}

#[derive(strum_macros::Display, Debug, Serialize, Deserialize)]
pub enum LogLevel {
    #[strum(serialize = "error")]
    Error,
    #[strum(serialize = "warn")]
    Warn,
    #[strum(serialize = "info")]
    Info,
    #[strum(serialize = "debug")]
    Debug,
    #[strum(serialize = "trace")]
    Trace,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(default)]
pub struct LspConfiguration {
    // 用户工作目录的路径
    pub workspace_folder: Option<Url>,
    // 插件安装的根路径
    pub extension_path: String,
    // 当前工具链
    pub tool_chain: String,

    // if true, recursively search the working directory for files to run diagnostics on
    pub auto_search_workdir: bool,
    // list of directories with header files
    pub include_dirs: Vec<String>,
    // list of directories to recursively search for SystemVerilog/Verilog sources
    pub source_dirs: Vec<String>,
    

    // 下方是和 linter 相关的配置
    // vlog 的诊断配置
    pub vlog_linter_configuration: DigitalLinterConfiguration,
    // vhdl 的诊断配置
    pub vhdl_linter_configuration: DigitalLinterConfiguration,
    // svlog 的诊断配置
    pub svlog_linter_configuration: DigitalLinterConfiguration,
    // log level
    pub log_level: LogLevel
}

impl Default for LspConfiguration {
    fn default() -> Self {
        LspConfiguration {
            workspace_folder: None,
            extension_path: "".to_string(),
            tool_chain: "xilinx".to_string(),
            auto_search_workdir: true,
            include_dirs: Vec::new(),
            source_dirs: Vec::new(),
            vlog_linter_configuration: DigitalLinterConfiguration::new("verilog"),
            vhdl_linter_configuration: DigitalLinterConfiguration::new("vhdl"),
            svlog_linter_configuration: DigitalLinterConfiguration::new("systemverilog"),
            log_level: LogLevel::Info,
        }
    }
}


#[tower_lsp::async_trait]
impl LanguageServer for Backend {
    async fn initialize(&self, params: InitializeParams) -> Result<InitializeResult> {
        // 申明 LSP 的基本信息和提供的能力
        let mut version = "0.4.0".to_string();
        let root_uri = &params.root_uri;

        let mut configure = self.server.configuration.write().unwrap();
        configure.workspace_folder = root_uri.clone();

        if let Some(serde_json::Value::Object(options)) = params.initialization_options {
            let extension_path = options.get("extensionPath").unwrap().as_str().unwrap();
            let tool_chain = options.get("toolChain").unwrap().as_str().unwrap();
            version = options.get("version").unwrap().as_str().unwrap().to_string();
            configure.tool_chain = tool_chain.to_string();
            configure.extension_path = extension_path.to_string();
        }

        let server_info = Some(ServerInfo {
            name: "Digital IDE 专用 LSP 后端服务器".to_string(),
            version: Some(version.to_string())
        });

        info!("当前客户端初始化结果");
        info!("workspaceFolder: {:?}", configure.workspace_folder);
        info!("extensionPath: {:?}", configure.extension_path);
        info!("toolChain: {:?}", configure.tool_chain);

        // 初始化原语系统
        self.server.srcs.init_primitive(
            &configure.tool_chain,
            &configure.extension_path
        );

        self.server.srcs.init_vhdl_project(&configure.extension_path);

        // 初始化系统缓存路径
        self.server.cache.start(&version);

        let text_document_sync = TextDocumentSyncCapability::Options(
            TextDocumentSyncOptions {
                open_close: Some(true),
                change: Some(TextDocumentSyncKind::INCREMENTAL),
                will_save: None,
                will_save_wait_until: None,
                save: Some(TextDocumentSyncSaveOptions::SaveOptions(SaveOptions {
                    include_text: None,
                })),
            }
        );
        
        let completion_provider = CompletionOptions {
            resolve_provider: Some(false),
            trigger_characters: Some(vec![
                ".".to_string(),
                "$".to_string(),
                "`".to_string(),
                "\"".to_string(),
                "/".to_string()
            ]),
            work_done_progress_options: WorkDoneProgressOptions {
                work_done_progress: None,
            },
            all_commit_characters: None,
            // TODO: 检查这里的选项
            completion_item: None,
        };

        let workspace = WorkspaceServerCapabilities {
            workspace_folders: Some(WorkspaceFoldersServerCapabilities {
                supported: Some(true),
                change_notifications: Some(OneOf::Left(true)),
            }),
            ..Default::default()
        };

        let capabilities = ServerCapabilities {
            text_document_sync: Some(text_document_sync),
            completion_provider: Some(completion_provider),
            definition_provider: Some(OneOf::Left(true)),
            hover_provider: Some(HoverProviderCapability::Simple(true)),
            inlay_hint_provider: Some(OneOf::Left(true)),
            document_symbol_provider: Some(OneOf::Left(true)),
            document_highlight_provider: Some(OneOf::Left(true)),
            workspace: Some(workspace),
            code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }),
            ..ServerCapabilities::default()
        };

        Ok(InitializeResult {
            server_info,
            capabilities,
            offset_encoding: None
        })
    }
    
    async fn initialized(&self, _: InitializedParams) {
        self.client
            .log_message(MessageType::INFO, "Digital LSP initialized!")
            .await;    
    }
    
    async fn execute_command(&self, params: ExecuteCommandParams) -> Result<Option<serde_json::Value>> {
        crate::execute_command::execute_command(self, params).await
    }

    async fn shutdown(&self) -> Result<()> {
        Ok(())
    }

    async fn did_open(&self, params: DidOpenTextDocumentParams) {
        // // 如果文件太大则显示错误
        // if CacheManager::uri_is_big_file(&params.text_document.uri) {
        //     self.client.show_message(MessageType::WARNING, "考虑到性能问题，对于大于 1MB 的文件不会主动提供语言服务")
        //     .await;
        // } else {
            let diagnostics = self.server.did_open(params);        
            self.client.publish_diagnostics(
                    diagnostics.uri,
                    diagnostics.diagnostics,
                    diagnostics.version,
                )
                .await;
        // }
    }

    async fn did_close(&self, params: DidCloseTextDocumentParams) {
        // 获取诊断相关的配置信息，如果 mode 为 common，则需要清空关闭文件的诊断信息
        let linter_mode = self.server.srcs.get_lsp_configuration_string_value("digital-ide.function.lsp.linter.linter-mode").unwrap();
        if linter_mode == "common" {
            self.client.publish_diagnostics(params.text_document.uri, vec![], None).await;               
        }
    }
    
    async fn did_change(&self, params: DidChangeTextDocumentParams) {
        // // 如果文件太大则显示错误
        // if CacheManager::uri_is_big_file(&params.text_document.uri) {
        //     // self.client.show_message(MessageType::WARNING, "考虑到性能问题，对于大于 1MB 的文件不会主动提供语言服务")
        //     // .await;
        // } else {
            self.server.did_change(params);
        // }
    }

    async fn did_delete_files(&self, params: DeleteFilesParams) {
        self.server.did_delete_files(params);
    }

    async fn did_save(&self, params: DidSaveTextDocumentParams) {
        // if CacheManager::uri_is_big_file(&params.text_document.uri) {

        // } else {
            let diagnostics = self.server.did_save(params);
            self.client
                .publish_diagnostics(
                    diagnostics.uri,
                    diagnostics.diagnostics,
                    diagnostics.version,
                )
                .await;
        // }
    }

    async fn completion(&self, params: CompletionParams) -> Result<Option<CompletionResponse>> {
        Ok(self.server.completion(params))
    }

    async fn goto_definition(
        &self,
        params: GotoDefinitionParams,
    ) -> Result<Option<GotoDefinitionResponse>> {
        Ok(self.server.goto_definition(params))
    }
    
    async fn hover(&self, params: HoverParams) -> Result<Option<Hover>> {
        Ok(self.server.hover(params))
    }

    async fn formatting(&self, params: DocumentFormattingParams) -> Result<Option<Vec<TextEdit>>> {
        Ok(self.server.formatting(params))
    }

    async fn range_formatting(
        &self,
        params: DocumentRangeFormattingParams,
    ) -> Result<Option<Vec<TextEdit>>> {
        Ok(self.server.range_formatting(params))
    }

    async fn document_symbol(
        &self,
        params: DocumentSymbolParams,
    ) -> Result<Option<DocumentSymbolResponse>> {
        Ok(self.server.document_symbol(params))
    }

    async fn document_highlight(
        &self,
        params: DocumentHighlightParams,
    ) -> Result<Option<Vec<DocumentHighlight>>> {
        Ok(self.server.document_highlight(params))
    }

    async fn inlay_hint(
        &self,
        params: InlayHintParams
    ) -> Result<Option<Vec<InlayHint>>> {
        Ok(self.server.inlay_hint(params))
    }

    async fn code_lens(
        &self,
        params: CodeLensParams
    ) -> Result<Option<Vec<CodeLens>>> {
        Ok(self.server.code_lens(params))
    }
}
