return {
    "neovim/nvim-lspconfig",
    event = { "BufReadPre", "BufNewFile" },
    dependencies = {
        { "antosha417/nvim-lsp-file-operations",      config = true },
        { "williamboman/mason.nvim",                  config = true },
        { "williamboman/mason-lspconfig.nvim" },
        { "WhoIsSethDaniel/mason-tool-installer.nvim" },
        { "j-hui/fidget.nvim",                        opts = {} },
        { "folke/neodev.nvim",                        opts = {} },
    },
    config = function()
        local lspconfig = require("lspconfig")
        local util = require("lspconfig.util")

        local keymap = vim.keymap

        vim.api.nvim_create_autocmd("LspAttach", {
            group = vim.api.nvim_create_augroup("lsp-attach", { clear = true }),
            callback = function(event)
                local opts = { noremap = true, silent = true }
                opts.desc = "Show LSP references"
                keymap.set("n", "gr", "<cmd>Telescope lsp_references<CR>", opts)

                opts.desc = "Go to declaration"
                keymap.set("n", "gD", vim.lsp.buf.declaration, opts)

                opts.desc = "Show LSP definitions"
                keymap.set("n", "gd", "<cmd>Telescope lsp_definitions<CR>", opts)

                opts.desc = "Show LSP implementations"
                keymap.set("n", "gi", "<cmd>Telescope lsp_implementations<CR>", opts)

                opts.desc = "Show LSP type definitions"
                keymap.set("n", "gt", "<cmd>Telescope lsp_type_definitions<CR>", opts)

                opts.desc = "See available code actions"
                keymap.set({ "n", "v" }, "<leader>ca", vim.lsp.buf.code_action, opts)

                opts.desc = "Smart rename"
                keymap.set("n", "<leader>rn", vim.lsp.buf.rename, opts)

                opts.desc = "Show buffer diagnostics"
                keymap.set("n", "<leader>D", "<cmd>Telescope diagnostics bufnr=0<CR>", opts)

                opts.desc = "Show line diagnostics"
                keymap.set("n", "<leader>d", vim.diagnostic.open_float, opts)

                opts.desc = "Go to previous diagnostic"
                keymap.set("n", "[d", vim.diagnostic.goto_prev, opts)

                opts.desc = "Go to next diagnostic"
                keymap.set("n", "]d", vim.diagnostic.goto_next, opts)

                opts.desc = "Go to previous diagnostic (error only)"
                keymap.set("n", "[e", function()
                    vim.diagnostic.goto_prev({ severity = vim.diagnostic.severity.ERROR })
                end, opts)

                opts.desc = "Go to next diagnostic (error only)"
                keymap.set("n", "]e", function()
                    vim.diagnostic.goto_next({ severity = vim.diagnostic.severity.ERROR })
                end, opts)

                opts.desc = "Show documentation for what is under cursor"
                keymap.set("n", "K", vim.lsp.buf.hover, opts)

                local client = vim.lsp.get_client_by_id(event.data.client_id)
                if client and client.server_capabilities.documentHighlightProvider then
                    vim.api.nvim_create_autocmd("LspDetach", {
                        group = vim.api.nvim_create_augroup("lsp-detach", { clear = true }),
                        callback = function(event2)
                            vim.lsp.buf.clear_references()
                        end,
                    })
                end
            end,
        })

        local capabilities = vim.lsp.protocol.make_client_capabilities()
        capabilities = vim.tbl_deep_extend(
            "force",
            capabilities,
            -- require('blink.cmp').get_lsp_capabilities(),
            require('cmp_nvim_lsp').default_capabilities()
        )

        local base_path = ""
        if (vim.loop.fs_stat("/usr/lib/node_modules")) then
            base_path = "/usr/lib/node_modules"
        elseif (vim.loop.fs_stat("/usr/local/lib/node_modules")) then
            base_path = "/usr/local/lib/node_modules"
        elseif (vim.loop.fs_stat("/opt/homebrew/lib/node_modules")) then
            base_path = "/opt/homebrew/lib/node_modules"
        end

        local function get_typescript_server_path(root_dir)
            local global_ts = base_path .. "/typescript/lib"
            local found_ts = ""
            local function check_dir(path)
                found_ts = util.path.join(path, "node_modules", "typescript", "lib")
                if vim.loop.fs_stat(found_ts) then
                    return path
                end
            end

            if util.search_ancestors(root_dir .. '/frontend/node_modules', check_dir) then
                return found_ts
            end

            if util.search_ancestors(root_dir .. '/node_modules', check_dir) then
                return found_ts
            end

            return global_ts
        end

        local path = util.path

        local function organize_imports()
            local params = {
                command = "_typescript.organizeImports",
                arguments = { vim.api.nvim_buf_get_name(0) },
                title = ""
            }
            vim.lsp.buf.execute_command(params)
        end

        local servers = {
            ts_ls = {
                init_options = {
                    plugins = {
                        {
                            name = "@vue/typescript-plugin",
                            location = base_path .. "/@vue/typescript-plugin",
                            languages = { "javascript", "typescript", "vue", "react" },
                        },
                    },
                },
                filetypes = {
                    "javascript",
                    "typescript",
                    "vue",
                    "typescriptreact",
                },
                commands = {
                    OrganizeImports = {
                        organize_imports,
                        description = "Organize Imports"
                    }
                },
                on_new_config = function(new_config, new_root_dir)
                    if get_typescript_server_path then
                        new_config.init_options.typescript = new_config.init_options.typescript or {}
                        new_config.init_options.typescript.tsdk = get_typescript_server_path(new_root_dir)
                    else
                        vim.notify("get_typescript_server_path is not defined", vim.log.levels.ERROR)
                    end
                end,
            },

            -- volar = {
            --     filetypes = {
            --         "javascript",
            --         "typescript",
            --         "vue",
            --     },
            --     on_new_config = function(new_config, new_root_dir)
            --         new_config.init_options.typescript.tsdk = get_typescript_server_path(new_root_dir)
            --     end,
            -- },

            cssls = {},

            intelephense = {
                root_dir = function(pattern)
                    ---@diagnostic disable-next-line: undefined-field
                    local cwd = vim.loop.cwd()
                    local root = util.root_pattern("composer.json")(pattern)

                    -- prefer cwd if root is a descendant
                    return util.path.is_descendant(cwd, root) and cwd or root
                end,
                init_options = {
                    licenceKey = vim.fn.expand("$HOME/.local/share/nvim/intelephense-licence.txt"),
                },
                settings = {
                    intelephense = {
                        format = {
                            enable = true,
                            sortUseStatements = false,
                        },
                    },
                },
            },

            gopls = {
                cmd = { "gopls" },
                filetypes = { "go", "gomod", "gowork", "gotmpl" },
                root_dir = util.root_pattern("go.work", "go.mod", ".git"),
                settings = {
                    gopls = {
                        completeUnimported = true,
                        usePlaceholders = true,
                        analyses = {
                            unusedparams = true,
                        },
                    },
                },
            },

            lua_ls = {
                settings = { -- custom settings for lua
                    Lua = {
                        -- make the language server recognize "vim" global
                        diagnostics = {
                            globals = { "vim" },
                        },
                        workspace = {
                            -- make language server aware of runtime files
                            library = {
                                [vim.fn.expand("$VIMRUNTIME/lua")] = true,
                                [vim.fn.stdpath("config") .. "/lua"] = true,
                            },
                        },
                    },
                },
            },

            dartls = {
                cmd = { "dart", "language-server", "--protocol=lsp" },
            },

            rust_analyzer = {
                diagnostics = {
                    enable = false,
                },
            },

            pyright = {
                -- before_init = function(_, config)
                --     config.settings.python.pythonpath = get_python_path(config.root_dir)
                -- end
            },

            yamlls = {
                settings = {
                    yaml = {
                        keyOrdering = false,
                    },
                },
            },
        }

        require("mason").setup()

        local ensure_installed = vim.tbl_keys(servers or {})
        vim.list_extend(ensure_installed, {
            "stylua",
            "prettier",
            "prettierd",
            "eslint",
            "eslint_d",
            "jsonlint",
            "markdownlint",
            "phpcbf",
            "phpcs",
            "golangci-lint",
            "hadolint",
            "gofumpt",
            "goimports",
        })

        require("mason-tool-installer").setup({
            ensure_installed = ensure_installed,
            run_on_start = false,
        })

        require("mason-lspconfig").setup()

        for server_name, server in pairs(servers) do
            server.capabilities = vim.tbl_deep_extend("force", {}, capabilities, server.capabilities or {})
            lspconfig[server_name].setup(server)
        end
    end,
}