-- Ñ master race
vim.keymap.set('n', 'ñ', ';')
vim.keymap.set('n', 'Ñ', ',')
vim.keymap.set('n', '{q', ':cprev<CR>zz', { silent = true, desc="[Q]uickfix backward" })
vim.keymap.set('n', '{Q', ':cfirst<CR>', { silent = true })
vim.keymap.set('n', '{l', ':lprev<CR>zz', { silent = true, desc="[L]oclist backward" })
vim.keymap.set('n', '{o', ':call append(line(".")-1, "")<CR>', { silent = true })
vim.keymap.set('n', '{b', ':bprev<CR>', { silent = true, desc = 'Previous buffer' })
vim.keymap.set('n', '{t', ':tabfirst<CR>', { silent = true, desc = 'First Tab' })
vim.keymap.set('n', '}q', ':cnext<CR>zz', { silent = true, desc="[Q]uickfix forward" })
vim.keymap.set('n', '}Q', ':clast<CR>', { silent = true })
vim.keymap.set('n', '}l', ':lnext<CR>zz', { silent = true, desc="[L]oclist forward" })
vim.keymap.set('n', '}o', ':call append(line("."), "")<CR>', { silent = true })
vim.keymap.set('n', '}b', ':bnext<CR>', { silent = true, desc = 'Next buffer' })
vim.keymap.set('n', '}t', ':tablast<CR>', { silent = true, desc = 'Last Tab' })
vim.keymap.set('i', '<C-}>', '<C-]>', { silent = true })

-- Splits
vim.keymap.set('n', '<M-h>', '<C-w>h', { desc = 'Go to left window' })
vim.keymap.set('n', '<M-l>', '<C-w>l', { desc = 'Go to right window' })
vim.keymap.set('n', '<M-j>', '<C-w>j', { desc = 'Go to lower window' })
vim.keymap.set('n', '<M-k>', '<C-w>k', { desc = 'Go to upper window' })
vim.keymap.set('n', '<S-Left>', '<C-w>H', { silent = true, desc = 'Move window to the left' })
vim.keymap.set('n', '<S-Right>', '<C-w>L', { silent = true, desc = 'Move window to the right' })
vim.keymap.set('n', '<S-Down>', '<C-w>J', { silent = true, desc = 'Move window to the bottom' })
vim.keymap.set('n', '<S-Up>', '<C-w>K', { silent = true, desc = 'Move window to the top' })
vim.keymap.set('n', '<Left>', ':vertical resize -1<CR>', { silent = true, desc = 'Decrease window width' })
vim.keymap.set('n', '<Right>', ':vertical resize +1<CR>', { silent = true, desc = 'Increase window width' })
vim.keymap.set('n', '<Down>', ':resize +1<CR>', { silent = true, desc = 'Decrease window height' })
vim.keymap.set('n', '<Up>', ':resize -1<CR>', { silent = true, desc = 'Increase window height' })
vim.keymap.set('n', '<leader>|', ':vnew<CR>', { silent = true, desc = 'Split window below' })
vim.keymap.set('n', '<leader>-', ':new<CR>', { silent = true, desc = 'Split window right' })
vim.keymap.set('i', '<M-h>', '<Esc><C-w>h', { desc = 'Go to left window' })
vim.keymap.set('i', '<M-l>', '<Esc><C-w>l', { desc = 'Go to right window' })
vim.keymap.set('i', '<M-j>', '<Esc><C-w>j', { desc = 'Go to lower window' })
vim.keymap.set('i', '<M-k>', '<Esc><C-w>k', { desc = 'Go to upper window' })

-- Faster
vim.keymap.set('n', '<leader>s', ':w!<CR>', { silent = true, desc = 'Save' })
vim.keymap.set('n', '<leader>q', ':q!<CR>', { silent = true, desc = 'Quit' })
vim.keymap.set('n', '<leader>Q', ':qa!<CR>', { silent = true, desc = 'Quit all' })
vim.keymap.set('n', '<Leader>p', ':Lazy<CR>', { desc = 'Lazy' })
vim.keymap.set({ 'n', 'v' }, '<Bar>', 'gg', { silent = true, desc = 'Go to top of the file' })
vim.keymap.set({ 'n', 'v' }, '¿', 'G', { silent = true, desc = 'Go to bottom of the file' })

-- Centering
vim.keymap.set({ 'n', 'v' }, 'J', 'mzJ`z')

local center_keys = { 'n', 'N', '{', '}', '*', '[g', ']g', '[s', ']s', '[m', ']m' }
for _, key in ipairs(center_keys) do
  vim.keymap.set({ 'n', 'x' }, key, key .. 'zzzv', { desc = 'center after ' .. key })
end

vim.keymap.set({ 'n', 'x', 'o' }, 'n', "'Nn'[v:searchforward]", { expr = true, desc = 'Next search result' })
vim.keymap.set({ 'n', 'x', 'o' }, 'N', "'nN'[v:searchforward]", { expr = true, desc = 'Next search result' })

vim.keymap.set('n', '<C-d>', '<C-d>zz')
vim.keymap.set('n', '<C-u>', '<C-u>zz')

-- Formatting
vim.keymap.set('n', '<leader>=', 'ggVGgq', { silent = true })
vim.keymap.set('n', '<leader>0', 'vapJgqap', { silent = true })
vim.keymap.set('n', 'Q', 'gqap', { silent = true })
vim.keymap.set('x', 'Q', 'gq', { silent = true })

-- Line movements
vim.keymap.set('n', '<leader>j', ':m .+1<CR>==', { silent = true })
vim.keymap.set('n', '<leader>k', ':m .-2<CR>==', { silent = true })
vim.keymap.set('n', 'k', "v:count == 0 ? 'gk' : 'k'", { expr = true, silent = true })
vim.keymap.set('n', 'j', "v:count == 0 ? 'gj' : 'j'", { expr = true, silent = true })
vim.keymap.set({ 'n', 'v' }, '<Home>', 'g<Home>', { silent = true })
vim.keymap.set({ 'n', 'v' }, '<End>', 'g<End>', { silent = true })
vim.keymap.set({ 'n', 'v' }, '<leader>y', 'y$', { silent = true })
vim.keymap.set({ 'n', 'v' }, 'Y', 'yg_', { silent = true })
vim.keymap.set({ 'n', 'x' }, 'H', 'g^', { silent = true })
vim.keymap.set({ 'n', 'x' }, 'L', 'g$', { silent = true })
vim.keymap.set('i', '<C-j>', '<Esc>:m .+1<CR>==gi')
vim.keymap.set('i', '<C-k>', '<Esc>:m .-2<CR>==gi')
vim.keymap.set('i', '<Home>', '<C-o>g<Home>', { silent = true })
vim.keymap.set('i', '<End>', '<C-o>g<End>', { silent = true })
vim.keymap.set('v', '<C-j>', ":m '>+1<CR>gv=gv")
vim.keymap.set('v', '<C-k>', ':m <-2<CR>gv=gv')

-- Reverse ctrl+u
vim.keymap.set('i', '<C-u>', '<C-g>u<C-u>')
vim.keymap.set('i', '<C-w>', '<C-g>u<C-w>')
vim.keymap.set('i', ',', ',<C-g>u')
vim.keymap.set('i', '.', '.<C-g>u')
vim.keymap.set('i', ':', ':<C-g>u')
vim.keymap.set('i', ';', ';<C-g>u')
vim.keymap.set('i', '!', '!<C-g>u')
vim.keymap.set('i', '?', '?<C-g>u')

-- Visual indentation
vim.keymap.set('v', '>', '>gv', { silent = true })
vim.keymap.set('v', '<', '<gv', { silent = true })
vim.keymap.set('n', '>', '>>', { silent = true })
vim.keymap.set('n', '<', '<<', { silent = true })

-- Keep cursor at the bottom of the visual selection after you yank it.
vim.keymap.set('v', 'y', 'ygv<Esc>', { remap = true })

-- Don't overwrite register when pasting over visual selection.
vim.keymap.set('x', 'p', function()
  return 'pgv"' .. vim.v.register .. 'y'
end, { remap = false, expr = true })

-- Allow for repeating commands in visual mode
vim.keymap.set('x', '.', ':normal.<CR>', { silent = true })

-- Select all
vim.keymap.set('n', '<C-a>', 'ggVG', { silent = true })
vim.keymap.set('i', '<C-a>', '<Esc>ggVG', { silent = true })

-- Terminal
vim.keymap.set('t', '<Esc>', '<C-\\><C-n>')
vim.keymap.set('t', '<M-h>', '<C-\\><C-n><C-w>h')
vim.keymap.set('t', '<M-j>', '<C-\\><C-n><C-w>j')
vim.keymap.set('t', '<M-k>', '<C-\\><C-n><C-w>k')
vim.keymap.set('t', '<M-l>', '<C-\\><C-n><C-w>l')
vim.keymap.set('t', '<S-Space>', '<Space>')
vim.keymap.set('t', '<C-Space>', '<Space>')

-- Map <C-j> and <C-k> to scroll up and down autocompletion list in command mode
vim.keymap.set('c', '<C-j>', '<C-n>', { remap = true, silent = true })
vim.keymap.set('c', '<C-k>', '<C-p>', { remap = true, silent = true })

-- Loupe
vim.keymap.set({ 'n', 'x' }, '/', '/\\v')
vim.keymap.set({ 'n', 'x' }, '?', '?\\v')

-- Reselect latest changed, put, or yanked text
vim.keymap.set(
  'n',
  'gV',
  '"`[" . strpart(getregtype(), 0, 1) . "`]"',
  { expr = true, desc = 'Visually select changed text' }
)

-- Search inside visually highlighted text.
vim.keymap.set('x', 'g/', '<esc>/\\%V', { silent = false, desc = 'Search inside visual selection' })

-- Search visually selected text
vim.keymap.set('x', '*', [[y/\V<C-R>=escape(@", '/\')<CR><CR>]])
vim.keymap.set('x', '#', [[y?\V<C-R>=escape(@", '?\')<CR><CR>]])

-- diff mode
vim.keymap.set('n', 'gh', ':diffget //2<CR>')
vim.keymap.set('n', 'gl', ':diffget //3<CR>')
vim.keymap.set({ 'n', 'x' }, '<leader>g}', ':diffput<CR>')
vim.keymap.set({ 'n', 'x' }, '<leader>{g', ':diffget<CR>')

-- Write and quit typos
local typos = { 'W', 'Wq', 'WQ', 'Wqa', 'WQa', 'WQA', 'WqA', 'Q', 'Qa', 'QA' }
for _, cmd in ipairs(typos) do
  vim.api.nvim_create_user_command(cmd, function(opts)
    vim.api.nvim_cmd({
      cmd = cmd:lower(),
      bang = opts.bang,
      mods = { noautocmd = true },
    }, {})
  end, { bang = true })
end

-- Bye
vim.api.nvim_set_keymap('', 'q', '', {})
