-- only show virtual text for WARN and higher
vim.diagnostic.config({
  virtual_text = { severity = { min = vim.diagnostic.severity.WARN } }
})

local nvim_lsp = require('lspconfig')
local null_ls = require('null-ls')

local null_ls_sources = {
  null_ls.builtins.code_actions.gitsigns,
}

-- enable LS / null-ls sources based on executable presence
if vim.fn.executable("node_modules/.bin/eslint") == 1 then
  table.insert(null_ls_sources, null_ls.builtins.formatting.eslint_d)
  table.insert(null_ls_sources, null_ls.builtins.diagnostics.eslint_d)
  table.insert(null_ls_sources, null_ls.builtins.code_actions.eslint_d)
end


if vim.fn.executable("shellcheck") == 1 then
  table.insert(null_ls_sources, null_ls.builtins.diagnostics.shellcheck)
  table.insert(null_ls_sources, null_ls.builtins.code_actions.shellcheck)
end

if vim.fn.executable("deno") == 1 then
  nvim_lsp.denols.setup({
    on_attach = on_attach,
  });
end

if vim.fn.executable("gopls") == 1 then
  nvim_lsp.gopls.setup({
    on_attach = on_attach,
  });
elseif vim.fn.executable("gofmt") == 1 then
  table.insert(null_ls_sources, null_ls.builtins.formatting.gofmt)
end

if vim.fn.executable("node_modules/.bin/tsc") == 1 then
  require('typescript').setup({
    server = {
      flags = {
        debounce_text_changes = 150,
      },
      on_attach = function(client, bufnr)
        -- mark tsserver as not having formatting available as we rely on
        -- null-ls/eslint for that and having both available makes nvim ask us
        -- which LS to use everytime we format
        client.server_capabilities.documentFormattingProvider = false
        client.server_capabilities.documentRangeFormattingProvider = false

        on_attach(client, bufnr)

        -- override mappings for typescript
        local opts = { silent = true, buffer = bufnr }
        -- exclude import statements from reference search (may have false positives)
        vim.keymap.set('n', 'gr', '<cmd>Telescope lsp_references default_text=!import\\ <CR>', opts)
      end
    }
  })

  -- set compiler for :make
  vim.cmd("compiler! tsc")
end

if vim.fn.executable("solargraph") == 1 then
  nvim_lsp.solargraph.setup({
    on_attach = on_attach,
    init_options = {
      formatting = false,
    }
  })
end

local group = vim.api.nvim_create_augroup('LspFormatting', { clear = false })

null_ls.setup({
  sources = null_ls_sources,

  on_attach = function(client, bufnr)
    -- format on save
    if client.server_capabilities.documentFormattingProvider then
      for key, cmd in pairs(vim.api.nvim_get_autocmds({ group = group, buffer = bufnr })) do
        vim.api.nvim_del_autocmd(cmd.id)
      end
      vim.api.nvim_create_autocmd('BufWritePre', {
        group = group,
        buffer = bufnr,
        callback = function()
          vim.lsp.buf.format()
        end,
      })
    end
  end,
});

-- custom LSP servers
local configs = require('lspconfig.configs')

if not configs.elvish then
  configs.elvish = {
    default_config = {
      cmd = {'elvish', '--lsp'},
      filetypes = {'elvish'},
      root_dir = nvim_lsp.util.root_pattern('*.elv'),
      settings = {},
    },
  }
end

nvim_lsp.elvish.setup({
  on_attach = on_attach,
})

-- show LSP progress bar
require('fidget').setup()