vim.g.coq_settings = {
    -- auto_start = 'shut-up',
    keymap = {
        eval_snips = "<Leader>se",
    },
    clients = {
        buffers = {
            enabled = true,
            weight_adjust = -2.0,
        },
        tree_sitter = {
            enabled = true,
            weight_adjust = -1.5,
        },
        lsp = {
            enabled = true,
            weight_adjust = 1.5,
        },
        snippets = {
            enabled = true,
            weight_adjust = 2.0,
        }
    }
}

local coq = require('coq')

require('coq_3p') {
    { src = 'vimtex',  short_name = 'TEX' },
    { src = 'nvimlua', short_name = 'NLUA', conf_only = true },
    { src = 'bc',      short_name = 'CALC', precision = 8 },
}


local lspstatus = require('lsp-status')
lspstatus.register_progress()

local function find_repo_root(names)
    local util = vim.lsp.config.util
    local config = names.configfiles
    local function matcher(filename, _bufnr)
        local gitroot = util.root_pattern('.git')(filename)
        if gitroot then
            for _, file in ipairs(config) do
                if util.path.is_file(util.path.join(gitroot, file)) then
                    return gitroot
                end
            end
        end
        return util.root_pattern(unpack(config))(filename)
    end

    return matcher
end

local lsp_confs = {
    lua_ls = {
        settings = {
            Lua = {
                -- Settings for working with nvim (copied from https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md#sumneko_lua)
                runtime = {
                    version = 'LuaJIT',
                    path = runtime_path,
                },
                diagnostics = {
                    globals = { 'vim' },
                },
                workspace = {
                    library = vim.api.nvim_get_runtime_file("", true),
                },
            },
        },
    },
    solidity_ls = {},
    coq_lsp = {},
    racket_langserver = {},
    ocamllsp = {},
    rust_analyzer = {
        cmd_env = {
            CARGO_TARGET_DIR = "/tmp/rust-analyzer"
        },
        settings = {
            ["rust-analyzer"] = {
                checkOnSave = true,
                -- checkOnSave = {
                --     command = "clippy",
                --     allTargets = false,
                -- },
                cargo = {
                    features = "all",
                }

            },
        },
    },
    ccls = {},
    jedi_language_server = {
        filetypes = { "python", "sage.python" },
    },
    gopls = {},
    dartls = {},
    ts_ls = {
        root_dir = find_repo_root({
            configfiles = { "tsconfig.json", "jsconfig.json", "package.json" }
        }),
    },
    denols = {
        root_dir = find_repo_root({
            configfiles = { "deno.json", "deno.jsonc" }
        }),
    },
    astro = {
        root_dir = find_repo_root({
            configfiles = { "astro.config.mjs" }
        }),
    },
    -- nargo = {
    --     root_dir = find_repo_root({
    --         configfiles = { "Nargo.toml" }
    --     }),
    -- },
    eslint = {
        root_dir = find_repo_root({
            configfiles = { ".eslintrc", ".eslintrc.js", "package.json" }
        }),
        on_new_config = function(config, new_root_dir)
            local default_config = vim.lsp.config.eslint.default_config
            default_config.on_new_config(config, new_root_dir)

            local util = vim.lsp.config.util
            local pnp_cjs = util.path.join(new_root_dir, '.pnp.cjs')
            local pnp_js = util.path.join(new_root_dir, '.pnp.js')
            if util.path.exists(pnp_cjs) or util.path.exists(pnp_js) then
                config.cmd = { 'yarn', 'exec', unpack(default_config.cmd) }
            end
        end
    },
    svelte = {},
    svls = {},
}

local lsp_special_setup = {
}

local function on_attach(client, _bufnr)
    lspstatus.on_attach(client)
end


for server, conf in pairs(lsp_confs) do
    local source_on_attach = conf.on_attach
    if source_on_attach == nil then
        conf.on_attach = on_attach
    else
        conf.on_attach = function(client, bufnr)
            on_attach(client, bufnr)
            source_on_attach(client, bufnr)
        end
    end

    conf.capabilities = vim.tbl_deep_extend(
        "keep",
        conf.capabilities or {},
        lspstatus.capabilities
    )

    -- local final_config = coq.lsp_ensure_capabilities(conf)
    local final_config = conf

    local special_setup = lsp_special_setup[server]
    if special_setup then
        special_setup(final_config)
    else
        vim.lsp.config[server] = final_config
        vim.lsp.enable(server)
    end
end

-- local null_ls = require('null-ls')
-- null_ls.setup({
--     sources = {
--         -- null_ls.builtins.diagnostics.chktex,
--         null_ls.builtins.diagnostics.cppcheck,
--         null_ls.builtins.diagnostics.shellcheck,
--
--         null_ls.builtins.code_actions.gitsigns,
--     },
-- })

vim.diagnostic.config({
    severity_sort = true,
    update_in_insert = true,
    float = {
        source = true,
    },
})

do -- signs
    local signs = {
        { 'DiagnosticSignError', text = '×', texthl = 'DiagnosticSignError' },
        { 'DiagnosticSignWarn',  text = '>', texthl = 'DiagnosticSignWarn' },
        { 'DiagnosticSignInfo',  text = 'I', texthl = 'DiagnosticSignInfo' },
        { 'DiagnosticSignHint',  text = 'H', texthl = 'DiagnosticSignHint' },
    }
    for _, sign in pairs(signs) do
        local name = sign[1]
        local opts = sign
        opts[1] = nil
        vim.fn.sign_define(name, opts)
    end
end

local map = vim.api.nvim_set_keymap
map(
    'n',
    'K',
    [[luaeval('next(vim.lsp.buf_get_clients()) == nil') ? 'K' : '<Cmd>lua vim.lsp.buf.hover()<CR>']],
    { noremap = true, expr = true }
)
map(
    'n',
    '<C-]>',
    [[luaeval('next(vim.lsp.buf_get_clients()) == nil') ? '<C-]>' : '<Cmd>lua vim.lsp.buf.definition()<CR>']],
    { noremap = true, expr = true }
)

local M = {}

M.format_on_save_hook = function()
    local enabled = vim.b.format_on_save
    if enabled == nil then
        enabled = true
    end
    if enabled ~= 0 and enabled ~= false then
        if vim.bo.filetype ~= "plaintex" and vim.bo.filetype ~= "tex" and vim.bo.filetype ~= "latex" and
            vim.bo.filetype ~= "qf" and vim.bo.filetype ~= "bib" and vim.bo.filetype ~= "" and vim.bo.filetype ~= "pdf"
            and vim.bo.filetype ~= "conf" and vim.bo.filetype ~= "TelescopePrompt" then
            vim.lsp.buf.format({ async = false })
        end
    end
end

vim.cmd [[
    augroup hoverlspconfig
        au!
        " diagnostic on hover
        au BufWritePre * lua require'lsp'.format_on_save_hook()
        au CursorHold * lua vim.diagnostic.open_float({focus = false})
    augroup END
]]

vim.api.nvim_create_autocmd(
    { 'FileType',
    }, {
        pattern = "*",
        callback = function()
            if vim.bo.filetype ~= "plaintex" and vim.bo.filetype ~= "tex" and vim.bo.filetype ~= "latex" and
                vim.bo.filetype ~= "qf" and vim.bo.filetype ~= "bib" and vim.bo.filetype ~= "" and vim.bo.filetype ~= "pdf"
                and vim.bo.filetype ~= "conf" and vim.bo.filetype ~= "TelescopePrompt" then
	    vim.defer_fn(function()
                if vim.fn.exists(":COQnow") > 0 then
                    vim.cmd([[ :COQnow -s ]])
                end
            end, 10)
            end
        end
    })


for _, method in ipairs({ 'textDocument/diagnostic', 'workspace/diagnostic' }) do
    local default_diagnostic_handler = vim.lsp.handlers[method]
    vim.lsp.handlers[method] = function(err, result, context, config)
        if err ~= nil and err.code == -32802 then
            return
        end
        return default_diagnostic_handler(err, result, context, config)
    end
end

-- vim.api.nvim_create_autocmd({ 'FileType', 'BufRead', 'BufReadPre', 'BufReadPost', 'BufWrite', 'BufWritePre',
--     'BufWritePost' }, {
--     pattern = "*",
--     callback = function()
--         if vim.bo.filetype ~= "plaintex" and vim.bo.filetype ~= "tex" and vim.bo.filetype ~= "latex" then
--             vim.cmd [[ :COQnow -s ]]
--         end
--     end
-- })

-- vim.cmd [[
--     augroup disabletexlsp
--         autocmd!
--         autocmd FileType tex :COQstop
--     augroup END
-- ]]

return M
