local map = vim.keymap.set
local silent = { silent = true }

-- Clear search highlighting on Escape
map("n", "<Esc>", "<cmd>nohlsearch<cr>", silent)

-- Visual line navigation
for _, mode in ipairs({ "n", "v" }) do
    map(mode, "j", "gj", silent)
    map(mode, "k", "gk", silent)
end

-- Hover: diagnostics on current line if any, else LSP hover
map("n", "K", function()
    local line = vim.api.nvim_win_get_cursor(0)[1] - 1
    if #vim.diagnostic.get(0, { lnum = line }) > 0 then
        vim.diagnostic.open_float()
    else
        vim.lsp.buf.hover()
    end
end, { desc = "Hover (diagnostic or LSP)" })

-- LSP
map("n", "<leader>gf",
    function() require("conform").format({ lsp_format = "fallback" }) end,
    { desc = "Format buffer" })
map("n", "<leader>gd", vim.lsp.buf.definition)
map("n", "<leader>gD", vim.lsp.buf.declaration)
map("n", "<leader>ca", vim.lsp.buf.code_action, { desc = "Code Action" })
map("n", "<leader>rn", vim.lsp.buf.rename, { desc = "Rename symbol" })

-- Trouble
map("n", "<leader>xx", "<cmd>Trouble diagnostics toggle focus=true<cr>",
    { desc = "Diagnostics (Trouble)" })
map("n", "<leader>xX", "<cmd>Trouble diagnostics toggle filter.buf=0 focus=true<cr>",
    { desc = "Buffer Diagnostics (Trouble)" })
map("n", "<leader>xt", "<cmd>Trouble todo toggle<cr>", { desc = "Todo (Trouble)" })

-- Pickers / files
map("n", "<C-f>", "<cmd>Pick files<cr>")
map("n", "<C-g>", "<cmd>Pick grep_live<cr>")
map("n", "<C-h>", "<cmd>Pick help<cr>")
map("n", "<C-e>", "<cmd>Oil<cr>")
map("n", "<C-k>", "<cmd>Pick keymaps<cr>")

-- DAP
map("n", "<leader>duo", function() require("dapui").open() end)
map("n", "<leader>duc", function() require("dapui").close() end)
map("n", "<leader>dbp", function() require("dap").toggle_breakpoint() end)
map("n", "<leader>drc", function() require("dap").run_to_cursor() end)

-- Bufferline
map("n", "<S-h>", "<cmd>BufferLineCyclePrev<cr>", silent)
map("n", "<S-l>", "<cmd>BufferLineCycleNext<cr>", silent)
map("n", "[b", "<cmd>BufferLineCyclePrev<cr>", silent)
map("n", "]b", "<cmd>BufferLineCycleNext<cr>", silent)
map("n", "<", "<cmd>BufferLineMovePrev<cr>", silent)
map("n", ">", "<cmd>BufferLineMoveNext<cr>", silent)
map("n", "<leader>bp", "<cmd>BufferLineTogglePin<cr>", { desc = "Toggle pin" })
map("n", "<leader>bP", "<cmd>BufferLineGroupClose ungrouped<cr>", { desc = "Close non-pinned" })
map("n", "<leader>bo", "<cmd>BufferLineCloseOthers<cr>", { desc = "Close others" })
map("n", "<leader>br", "<cmd>BufferLineCloseRight<cr>", { desc = "Close right" })
map("n", "<leader>bl", "<cmd>BufferLineCloseLeft<cr>", { desc = "Close left" })
map("n", "<leader>bd", "<cmd>bdelete<cr>", { desc = "Delete buffer" })
map("n", "<leader>bb", "<cmd>BufferLinePick<cr>", { desc = "Pick buffer" })
map("n", "<leader>bse", "<cmd>BufferLineSortByExtension<cr>", { desc = "Sort by extension" })
map("n", "<leader>bsd", "<cmd>BufferLineSortByDirectory<cr>", { desc = "Sort by directory" })
map("n", "<leader>bsr", "<cmd>BufferLineSortByRelativeDirectory<cr>", { desc = "Sort by relative dir" })
map("n", "<leader>bst", "<cmd>BufferLineSortByTabs<cr>", { desc = "Sort by tabs" })
for i = 1, 9 do
    map("n", ("<leader>%d"):format(i), ("<cmd>BufferLineGoToBuffer %d<cr>"):format(i), silent)
end

-- Spell
map("n", "<leader>sc", function()
    vim.wo.spell = not vim.wo.spell
    vim.notify("Spell: " .. (vim.wo.spell and "ON" or "OFF"))
end, { desc = "Toggle spell" })

map("n", "<leader>sl", function()
    local cur = vim.opt.spelllang:get()[1] or ""
    local new = cur == "en" and "de" or "en"
    vim.opt.spelllang = new
    vim.notify("Spell lang: " .. new)
end, { desc = "Switch spell language" })
