-- See: https://neovim.io/doc/user/lsp.html#lsp-defaults
vim.keymap.del('n', 'grn')
vim.keymap.del({ 'n', 'v' }, 'gra')
vim.keymap.del('n', 'grr')
vim.keymap.del('n', 'gri')
vim.keymap.del('n', 'gO')
vim.keymap.del('i', '<c-s>')

local startswith = function(text, prefix)
	return text:find(prefix, 1, true) == 1
end

vim.api.nvim_create_autocmd('LspAttach', {
	callback = function(args)
		-- See: https://neovim.io/doc/user/lsp.html#lsp-defaults
		vim.lsp.config('*', require('blink.cmp').get_lsp_capabilities({}, false))

		-- Retrieve Dependencies
		local lsp_client = vim.lsp.get_client_by_id(args.data.client_id)
		local buf = args.buf

		-- LSP: Code Completion
		if lsp_client:supports_method('textDocument/completion') then
			vim.lsp.completion.enable(true, lsp_client.id, buf, { autotrigger = false })
		end

		-- LSP: Diagnostics
		if lsp_client:supports_method('textDocument/diagnostic') then
			vim.keymap.set('n', '<leader>le', function()
				require('snacks').picker.diagnostics_buffer()
			end, { buffer = buf, desc = '[L]SP [E]rrors' })
		end

		-- LSP: Diagnostics
		if lsp_client:supports_method('textDocument/signatureHelp') then
			vim.keymap.set('i', '<c-s>', vim.lsp.buf.signature_help, { buffer = buf, desc = 'LSP Signature Help' })
		end

		-- LSP Action: Formatting
		if lsp_client:supports_method('textDocument/formatting') or startswith(lsp_client.name, 'otter-ls') then
			vim.keymap.set('n', '<leader>lf', function()
				require('conform').format({
					async = true,
					bufnr = buf,
					id = lsp_client.id,
				})
			end, { buffer = buf, desc = '[L]SP [F]ormat' })
		end

		-- LSP Action: Inlay Hint
		--- WORKAROUND: otter-ls seems to crash with inlayHint.
		if lsp_client:supports_method('textDocument/inlayHint') and not startswith(lsp_client.name, 'otter-ls') then
			vim.lsp.inlay_hint.enable(true, { bufnr = buf })

			vim.keymap.set('n', '<leader>lh', function()
				if vim.lsp.inlay_hint.is_enabled({ bufnr = buf }) then
					vim.lsp.inlay_hint.enable(false, { bufnr = buf })
				else
					vim.lsp.inlay_hint.enable(true, { bufnr = buf })
				end
			end, { desc = '[L]SP Toggle Inlay [H]ints' })
		end

		-- LSP Action: Code Actions
		if lsp_client:supports_method('textDocument/codeAction') then
			vim.keymap.set('n', '<leader>li', function()
				vim.lsp.buf.code_action()
			end, { buffer = buf, desc = '[L]SP F[I]xes' })
		end

		-- LSP Action: Rename
		if lsp_client:supports_method('textDocument/rename') then
			vim.keymap.set('n', '<leader>lr', vim.lsp.buf.rename, { buffer = buf, desc = '[L]SP [R]ename' })
		end

		-- LSP Action: "Hover"
		if lsp_client:supports_method('textDocument/hover') then
			vim.keymap.set('n', 'K', vim.lsp.buf.hover, { buffer = buf, desc = '[L]SP Hover' })
		end

		-- LSP Action: References
		if
			lsp_client:supports_method('textDocument/references')
			or lsp_client:supports_method('textDocument/typeDefinition')
			or lsp_client:supports_method('textDocument/definition')
		then
			vim.keymap.set('n', '<leader>ld', function()
				require('snacks').picker.smart({
					multi = {
						'lsp_definitions',
						'lsp_references',
						'lsp_implementations',
						'lsp_type_definitions',
					},
					format = 'file',
					matcher = {
						cwd_bonus = true,
						frecency = false,
						sort_empty = true,
					},
					transform = 'unique_file',
				})
			end, { buffer = buf, desc = '[L]SP Fin[D]er' })
		end

		-- LSP Action: List Buffer Symbols
		if lsp_client:supports_method('textDocument/documentSymbol') then
			vim.keymap.set('n', '<leader>ls', function()
				require('snacks').lsp_symbols()
			end, { buffer = buf, desc = '[L]SP [S]ymbols' })
		end
	end,
})