local lsp_lines = require("lsp_lines")
lsp_lines.setup()
-- Disable virtual_text since it's redundant due to lsp_lines.
vim.diagnostic.config({
  virtual_text = false,
})

-- The nvim-cmp almost supports LSP's capabilities so You should advertise it to LSP servers..
local capabilities = require("cmp_nvim_lsp").default_capabilities()

vim.o.foldcolumn = "1" -- '0' is not bad
vim.o.foldlevel = 99 -- Using ufo provider need a large value, feel free to decrease the value
vim.o.foldlevelstart = 99
vim.o.foldenable = true
vim.o.fillchars = [[eob: ,fold: ,foldopen:,foldsep: ,foldclose:]]
vim.o.statuscolumn = "%= "
  -- FIXME: figure out how to put on the other side without having to do a lot of shifting
  .. "%s" -- sign column
  .. "%{%" -- evaluate this, and then evaluate what it returns
  .. "&number ?"
  .. "(v:relnum ?"
  -- when showing relative numbers, make sure to pad so things don't shift as you move the cursor
  .. 'printf("%"..len(line("$")).."s", v:relnum)'
  .. ":"
  .. "v:lnum"
  .. ")"
  .. ":"
  .. '""'
  .. " " -- space between lines and fold
  .. "%}"
  .. "%= "
  .. "%#FoldColumn#" -- highlight group for fold
  .. "%{" -- expression for showing fold expand/colapse
  .. "foldlevel(v:lnum) > foldlevel(v:lnum - 1)" -- any folds?
  .. "? (foldclosed(v:lnum) == -1" -- currently open?
  .. '? ""' -- point down
  .. ':  ""' -- point to right
  .. ")"
  .. ': " "' -- blank for no fold, or inside fold
  .. "}"
  .. "%= " -- spacing between end of column and start of text

-- Using ufo provider need remap `zR` and `zM`. If Neovim is 0.6.1, remap yourself
require("which-key").register({
  z = {
    R = { require("ufo").openAllFolds, "Open all folds" },
    M = { require("ufo").closeAllFolds, "Close all folds" },
  },
})
-- Tell the server the capability of foldingRange,
-- Neovim hasn't added foldingRange to default capabilities, users must add it manually
capabilities.textDocument.foldingRange = {
  dynamicRegistration = false,
  lineFoldingOnly = true,
}
require("ufo").setup()

require("lspsaga").setup({
  symbol_in_winbar = {
    enable = false,
  },
  lightbulb = {
    enable = false,
    enable_in_insert = false,
  },
})

local lspconfig = require("lspconfig")
local on_attach_def = function(_, bufnr)
  require("which-key").register({
    K = { "<cmd>Lspsaga hover_doc ++quiet<cr>", "show info" },
    ["<leader>"] = {
      l = {
        d = { "<cmd>Lspsaga show_cursor_diagnostics<cr>", "open diagnostic window" },
        c = { "<cmd>Lspsaga code_action<cr>", "code action" },
        r = { "<cmd>Lspsaga rename<cr>", "rename" },
        i = { "<cmd>Lspsaga hover_doc ++keep<cr>", "show info (sticky)" },
        f = {
          function()
            vim.lsp.buf.format({ async = true })
          end,
          "format (lsp)",
          mode = { "n", "v" },
        },
      },
      t = {
        l = { lsp_lines.toggle, "lsp lines" },
      },
    },
    g = {
      d = { "<cmd>Lspsaga peek_definition<cr>", "Goto definition" },
      t = { "<cmd>Lspsaga peek_type_definition<cr>", "Goto type defininition" },
      h = { "<cmd>Lspsaga lsp_finder<CR>", "Lsp finder" },
      r = { "<cmd>Telescope lsp_references<cr>", "Goto reference" },
      D = { vim.lsp.buf.declaration, "Goto declaration" },
      I = { "<cmd>Telescope lsp_implementations<cr>", "Goto implementation" },
    },
    ["["] = {
      d = { "<cmd>Lspsaga diagnostic_jump_prev<cr>", "Previous diagnostic" },
    },
    ["]"] = {
      d = { "<cmd>Lspsaga diagnostic_jump_next<cr>", "Next diagnostic" },
    },
  }, { buffer = bufnr, silent = true })
end

local lspconfig_default_options = {
  on_attach = on_attach_def,
  capabilities = capabilities,
  flags = {
    debounce_text_changes = 100,
  },
}

---function to add default options to lspconfig
---@param lsp string
---@param options table
---@return nil
local function lspconfig_setup(lsp, options)
  local final_options = vim.tbl_deep_extend("force", lspconfig_default_options, options)
  lspconfig[lsp].setup(final_options)
end

local servers = {
  "bashls",
  "nil_ls",
  "pylsp",
  "ruff_lsp",
  "rust_analyzer",
}
for _, lsp in ipairs(servers) do
  lspconfig_setup(lsp, {})
end

lspconfig_setup("lua_ls", {
  settings = {
    Lua = {
      runtime = {
        -- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim)
        version = "LuaJIT",
      },
      diagnostics = {
        -- Get the language server to recognize the `vim` global
        globals = { "vim" },
      },
      workspace = {
        -- Make the server aware of Neovim runtime files
        library = vim.api.nvim_get_runtime_file("", true),
        checkThirdParty = false,
      },
      -- Do not send telemetry data containing a randomized but unique identifier
      telemetry = {
        enable = false,
      },
      format = {
        enable = false,
      },
    },
  },
})
