local ok, lspconfig = pcall(require, "lspconfig")

if not ok then
    return
end

local root_dir
for dir in vim.fs.parents(vim.api.nvim_buf_get_name(0)) do
    if vim.fn.isdirectory(dir .. "/.git") == 1 then
        root_dir = dir
        break
    end
end

vim.lsp.handlers["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, { border = "single" })

local capabilities = {}

local has_cmp, cmp_lsp = pcall(require, "cmp_nvim_lsp")
if has_cmp then
    capabilities = cmp_lsp.default_capabilities()
end

local has_lsp_format, lsp_format = pcall(require, "lsp-format")
if has_lsp_format then
    lsp_format.setup()
end

local on_attach = function(client, bufnr)
    require("my.keymaps").lsp_keymaps(client, bufnr)

    if client.server_capabilities.completionProvider then
        vim.api.nvim_buf_set_option(bufnr, "omnifunc", "v:lua.vim.lsp.omnifunc")
    end

    if client.server_capabilities.definitionProvider then
        vim.api.nvim_buf_set_option(bufnr, "tagfunc", "v:lua.vim.lsp.tagfunc")
    end

    -- Highlight on cursor hold
    if client.server_capabilities.documentHighlightProvider then
        vim.api.nvim_create_autocmd({ "CursorHold" }, {
            callback = vim.lsp.buf.document_highlight,
            buffer = bufnr,
        })
    end

    if client.server_capabilities.signatureHelp then
        vim.api.nvim_create_autocmd({ "CursorHoldI" }, {
            callback = vim.lsp.buf.signature_help,
            buffer = bufnr,
        })
    end

    vim.api.nvim_create_autocmd({ "CursorMoved" }, {
        callback = vim.lsp.buf.clear_references,
        buffer = bufnr,
    })

    if has_lsp_format then
        lsp_format.on_attach(client)
    end
end

local function prettier_command()
    if not root_dir then
        return "prettier"
    end

    if vim.fs.basename(root_dir .. "node_modules/prettier") then
        return "npx prettier"
    else
        return "prettier"
    end
end

local prettier = {
    formatCommand = prettier_command() .. [[ --stdin-filepath ${INPUT} ${--tab-width:tab_width}]],
    formatStdin = true,
}

local eslint = {
    lintCommand = [[eslint_d -f visualstudio --stdin --stdin-filename ${INPUT}]],
    lintIgnoreExitCode = true,
    lintStdin = true,
    lintFormats = {
        "%f(%l,%c): %tarning %m",
        "%f(%l,%c): %rror %m",
    },
    lintSource = "eslint",
}

local shellcheck = {
    lintCommand = "shellcheck -f gcc -x",
    lintSource = "shellcheck",
    lintFormats = {
        "%f:%l:%c: %trror: %m",
        "%f:%l:%c: %tarning: %m",
        "%f:%l:%c: %tote: %m",
    },
}

local servers = {
    efm = {
        filetypes = { "typescript", "typescriptreact", "sh", "php" },
        init_options = { documentFormatting = true },
        settings = {
            rootMarkers = { ".git/" },
            languages = {
                typescript = { prettier, eslint },
                typescriptreact = { prettier, eslint },
                sh = { shellcheck },
                php = { prettier },
            },
        },
    },
    gopls = {},
    nil_ls = {
        settings = {
            ['nil'] = {
                formatting = {
                    command = { "nixpkgs-fmt" },
                },
            },
        },
    },
    jedi_language_server = {}, -- python lsp
    ruff_lsp = {},             -- python linter
    rust_analyzer = {
        assist = {
            importGranularity = "module",
            importPrefix = "self",
        },
        cargo = {
            buildScripts = {
                enable = true,
            },
        },
        procMacro = {
            enable = true,
        },
    },
    lua_ls = {
        settings = {
            Lua = {
                runtime = {
                    version = "LuaJIT",
                },
                diagnostics = {
                    globals = { "vim" },
                },
                workspace = {
                    checkThirdParty = false,
                    library = vim.api.nvim_get_runtime_file("", true),
                },
                telemetry = {
                    enable = false,
                },
            },
        },
    },
    elixirls = {
        cmd = { "elixir-ls" },
        settings = {
            elixirLS = {
                dialyzerEnabled = true,
            },
        },
    },
    tsserver = {
        settings = {
            documentFormatting = false,
        },
    },
    psalm = {},
}

for lsp, settings in pairs(servers) do
    lspconfig[lsp].setup(vim.tbl_extend("force", {
        on_attach = on_attach,
        capabilities = capabilities,
    }, settings))
end