vim.diagnostic.config({
  -- Use the default configuration
  -- virtual_lines = true,

  -- Alternatively, customize specific options
  -- virtual_lines = {
  --  -- Only show virtual line diagnostics for the current cursor line
  --  current_line = true,
  -- },

  -- Open in floating window
  float = {
    source = "always",
    border = "shadow",
  },
})

require("nvim-web-devicons").setup {}

require("fidget").setup {
  progress = {
    display = {
      progress_icon = {
        pattern = "dots",
        period = 1,
      },
    },
  },
}

require("fzf-lua").setup {
  previewers = {
    builtin = {
      extensions = {
        ["png"] = { "chafa" },
        ["jpg"] = { "chafa" },
        ["jpeg"] = { "chafa" },
        ["gif"] = { "chafa" },
      },
    },
  },
}

vim.keymap.set("n", "<C-p>", "<cmd>lua require('fzf-lua').files()<CR>", { noremap = true, silent = true })
vim.keymap.set("n", "<C-g>", "<cmd>lua require('fzf-lua').git_status()<CR>", { noremap = true, silent = true })
vim.keymap.set("n", "<C-/>", "<cmd>lua require('fzf-lua').live_grep()<CR>", { noremap = true, silent = true })
vim.keymap.set("n", "<C-\\>", "<cmd>lua require('fzf-lua').buffers()<CR>", { noremap = true, silent = true })
vim.keymap.set("n", "<C-b>", "<cmd>lua require('fzf-lua').builtin()<CR>", { noremap = true, silent = true })
vim.keymap.set("n", "ca", "<cmd>lua require('fzf-lua').lsp_code_actions()<CR>", { noremap = true, silent = true })

require("nvim-treesitter.configs").setup {
  highlight = {
    enable = true,
    additional_vim_regex_highlighting = false,
  },
  indent = {
    enable = true,
    disable = { "c", "cpp" },
  }
}

require("conform").setup({
  formatters_by_ft = {
    c = { "clang-format" },
    cpp = { "clang-format" },
    rust = { "rustfmt" },
    python = { "ruff_fix", "ruff_format" },
    javascript = { "prettier" },
    typescript = { "prettier" },
    vue = { "prettier" },
  },
  format_on_save = {
    timeout_ms = 1000,
    lsp_format = "fallback",
  },
})

-- require("nvim-format-buffer").setup({
--   format_rules = {
--     { pattern = { "*.c", "*.h", "*.cpp", "*.hpp" }, command = "clang-format" },
--     { pattern = { "*.rs" }, command = "rustfmt" },
--     {
--       pattern = { "*.js", "*.mjs", "*.ts", "*.mts", "*.cjs", "*.tsx", "*.vue", "*.css" },
--       command = function()
--         return "prettier --stdin-filepath " .. vim.api.nvim_buf_get_name(0)
--       end,
--     },
--     { pattern = { "*.sql" }, command = "pg_format --spaces=2 --wrap-limit=1000 --no-rcfile" },
--     { pattern = { "*.py", "*.pyi" }, command = "ruff check --select I --fix --silent - | ruff format -" }
--   },
-- })

require("vim.lsp.log").set_format_func(vim.inspect)
vim.lsp.set_log_level("error")

vim.keymap.set("n", "[d", "<cmd>lua vim.diagnostic.jump({count = -1, float = true})<CR>", { noremap = true, silent = true })
vim.keymap.set("n", "]d", "<cmd>lua vim.diagnostic.jump({count = 1, float = true})<CR>", { noremap = true, silent = true })
vim.keymap.set("n", "[e", "<cmd>lua vim.diagnostic.jump({count = -1, severity = vim.diagnostic.severity.ERROR, float = true})<CR>", { noremap = true, silent = true })
vim.keymap.set("n", "]e", "<cmd>lua vim.diagnostic.jump({count = -1, severity = vim.diagnostic.severity.ERROR, float = true})<CR>", { noremap = true, silent = true })

vim.keymap.set("n", "gd", "<Cmd>lua vim.lsp.buf.definition()<CR>", { noremap = true, silent = true })
vim.keymap.set("n", "gD", "<Cmd>lua vim.lsp.buf.declaration()<CR>", { noremap = true, silent = true })
vim.keymap.set("n", "gh", "<cmd>lua vim.lsp.buf.signature_help()<CR>", { noremap = true, silent = true })
vim.keymap.set("n", "gI", "<cmd>lua vim.lsp.buf.implementation()<CR>", { noremap = true, silent = true })
vim.keymap.set("n", "gt", "<cmd>lua vim.lsp.buf.type_definition()<CR>", { noremap = true, silent = true })

vim.keymap.set("n", "gl", "<cmd>lua vim.diagnostic.reset()<CR>", { noremap = true, silent = true })

vim.lsp.enable("pyright")
vim.lsp.config("pyright", {})

vim.lsp.enable("hls")
vim.lsp.config("hls", {
  filetypes = { "haskell", "lhaskell", "cabal" }
})

local yarn_path = vim.fn.expand("$HOME/.config/yarn/global/node_modules")

vim.lsp.enable("vtsls")
vim.lsp.config("vtsls", {
  settings = {
    vtsls = {
      experimental = {
        completion = {
          enableServerSideFuzzyMatch = true,
          entriesLimit = 64,
        },
      },
      tsserver = {
        globalPlugins = {
          {
            configNamespace = "typescript",
            name = "@vue/typescript-plugin",
            location = yarn_path .. "/@vue/typescript-plugin",
            languages = { "vue" },
          },
        },
      },
    },
  },
  filetypes = {
    -- "javascript",
    "javascriptreact",
    -- "typescript",
    "typescriptreact",
    "vue",
  }
})

vim.lsp.enable("vue_ls")
vim.lsp.config("vue_ls", {
  init_options = {
    typescript = {
      tsdk = yarn_path .. "/typescript/lib",
    }
  }
})

vim.lsp.enable("golar")
vim.lsp.config("golar", {
  settings = {
  },
  filetypes = {
    "javascript",
    -- "javascriptreact",
    "typescript",
    -- "typescriptreact",
    -- "vue",
  }
})

vim.api.nvim_create_autocmd("FileType", {
  pattern = "vue",
  callback = function()
    vim.bo.commentstring = "<!-- %s -->"
  end,
})

vim.lsp.enable("clangd")
vim.lsp.config("clangd", {
  cmd = {
    "clangd",
    "--background-index",
    "--enable-config",
    "--query-driver=/usr/lib64/ccache/*,/usr/bin/*",
    "--log=error",
  },
  flags = {
    allow_incremental_sync = false,
  },
})

vim.lsp.enable("ruff")
vim.lsp.config("ruff", {})

vim.lsp.enable("rust_analyzer")
vim.lsp.config("rust_analyzer", {})

-- Automatic completion triggering
-- vim.api.nvim_create_autocmd("LspAttach", {
--   callback = function(ev)
--     local client = vim.lsp.get_client_by_id(ev.data.client_id)
--     if client:supports_method("textDocument/completion") then
--       vim.lsp.completion.enable(true, client.id, ev.buf, { autotrigger = true })
--     end
--   end,
-- })

-- local function check_back_space()
--   local col = vim.fn.col('.') - 1
--   return col <= 0 or vim.fn.getline('.'):sub(col, col):match('%s')
-- end
--
-- function tab_complete()
--   if check_back_space() then
--     return vim.api.nvim_replace_termcodes('<Tab>', true, false, true)
--   end
--   return vim.api.nvim_replace_termcodes('<C-p>', true, false, true)
-- end
--
-- vim.api.nvim_set_keymap('i', '<Tab>', 'v:lua.tab_complete()', { expr = true, noremap = true })
-- vim.api.nvim_set_keymap('i', '<S-Tab>', '<C-n>', { noremap = true })

local has_words_before = function()
  local col = vim.api.nvim_win_get_cursor(0)[2]
  if col == 0 then
    return false
  end
  local line = vim.api.nvim_get_current_line()
  return line:sub(col, col):match("%s") == nil
end

require("blink.cmp").setup {
  keymap = {
    preset = "none",

    ["<Tab>"] = {
      function(cmp)
        if not has_words_before() then
          vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<Tab>", true, true, true), "n", false)
          return true
        end
      end,
      "show", "select_next", "fallback" },
    ["<S-Tab>"] = { "show", "select_prev", "fallback" },
  },
  fuzzy = { implementation = "prefer_rust_with_warning" },
  completion = {
    menu = { auto_show = false },
    list = { selection = { preselect = false, auto_insert = true }, cycle = { from_top = true } },
  },
}
