local M = {}
local api = vim.api
local opts = { noremap = true, silent = true }

function M.treesitter()
    local mappings = {
        ['['] = {
            m = 'Previous start of outer class',
            M = 'Previous end of outer class',
            ['['] = 'Previous start of outer function',
            [']'] = 'Previous end of outer function',
        },
        [']'] = {
            m = 'Next start of outer class',
            M = 'Next end of outer class',
            ['['] = 'Next start of outer function',
            [']'] = 'Next end of outer function',
        },
        g = {
            t = {
                name = 'Treesitter',
                d = 'Goto definition',
                D = 'List definitions',
                i = 'Initialize selection',
                j = 'Goto previous usage',
                k = 'Goto next usage',
                o = 'List definitions TOC',
                r = 'Rename within scope',
            },
        },
    }
    local visual_mappings = {
        a = {
            c = 'Outer class',
            f = 'Outer function',
        },
        i = {
            c = 'Inner class',
            f = 'Inner function',
        },
        g = {
            t = {
                name = 'Treesitter',
                n = 'Increment node',
                s = 'Increment scope',
                m = 'Decrement node',
            },
        },
    }

    local wk = require('which-key')
    wk.register(mappings)
    wk.register(visual_mappings, { mode = 'x' })
end

function M.dial()
    api.nvim_set_keymap('n', '<C-a>', '<cmd>lua require("dial.map").inc_normal()', opts)
    api.nvim_set_keymap('x', '<C-a>', '<cmd>lua require("dial.map").inc_visual()', opts)
    api.nvim_set_keymap('n', '<C-x>', '<cmd>lua require("dial.map").dec_normal()', opts)
    api.nvim_set_keymap('x', '<C-x>', '<cmd>lua require("dial.map").dec_visual()', opts)
    api.nvim_set_keymap('x', 'g<C-a>', '<cmd>lua require("dial.map").inc_gvisual()', opts)
    api.nvim_set_keymap('x', 'g<C-x>', '<cmd>lua require("dial.map").dec_gvisual()', opts)
end

function M.gitlinker()
    api.nvim_set_keymap('n', '<leader>gY', '<cmd>lua require("gitlinker").get_repo_url()<CR>', opts)
end

function M.dap()
    api.nvim_set_keymap('n', '<leader>dn', '<cmd>lua require("dap").continue()<CR>', opts)
    api.nvim_set_keymap('n', '<leader>dd', '<cmd>lua require("dap").disconnect()<CR>', opts)
    api.nvim_set_keymap('n', '<leader>db', '<cmd>lua require("dap").toggle_breakpoint()<CR>', opts)
    api.nvim_set_keymap(
        'n',
        '<leader>dB',
        '<cmd>lua require("dap").set_breakpoint(vim.fn.input("Breakpoint condition: "))<CR>',
        opts
    )
    api.nvim_set_keymap('n', '<leader>dl', '<cmd>lua require("dap").list_breakpoints()<CR>', opts)
    api.nvim_set_keymap('n', '<leader>dc', '<cmd>lua require("dap").run_to_cursor()<CR>', opts)
    api.nvim_set_keymap('n', '<leader>dz', '<cmd>lua require("dap").run_last()<CR>', opts)
    api.nvim_set_keymap('n', '<F9>', '<cmd>lua require("dap").step_over()<CR>', opts)
    api.nvim_set_keymap('n', '<leader>dv', '<cmd>lua require("dap").step_over()<CR>', opts)
    api.nvim_set_keymap('n', '<F10>', '<cmd>lua require("dap").step_into()<CR>', opts)
    api.nvim_set_keymap('n', '<leader>di', '<cmd>lua require("dap").step_into()<CR>', opts)
    api.nvim_set_keymap('n', '<F11>', '<cmd>lua require("dap").step_out()<CR>', opts)
    api.nvim_set_keymap('n', '<leader>do', '<cmd>lua require("dap").step_out()<CR>', opts)
    api.nvim_set_keymap('n', '<leader>dr', '<cmd>lua require("dap").repl.open()<CR>', opts)
end

function M.dapui()
    api.nvim_set_keymap('n', '<leader>de', '<cmd>lua require("dapui").eval()<CR>', opts)
    api.nvim_set_keymap('x', '<leader>de', '<cmd>lua require("dapui").eval()<CR>', opts)
    api.nvim_set_keymap('n', '<leader>df', '<cmd>lua require("dapui").float_element()<CR>', opts)
    api.nvim_set_keymap('n', '<leader>dt', '<cmd>lua require("dapui").toggle()<CR>', opts)
end

function M.telescope_symbols()
    api.nvim_set_keymap(
        'n',
        '<leader>fjg',
        '<cmd>lua require("telescope.builtin").symbols{sources = {"gitmoji"}, prompt_title = "Gitmoji"}<CR>',
        opts
    )
    api.nvim_set_keymap(
        'n',
        '<leader>fjj',
        '<cmd>lua require("telescope.builtin").symbols{sources = {"emoji"}, prompt_title = "Emoji"}<CR>',
        opts
    )
    api.nvim_set_keymap(
        'n',
        '<leader>fjk',
        '<cmd>lua require("telescope.builtin").symbols{sources = {"kaomoji"}, prompt_title = "Kaomoji"}<CR>',
        opts
    )
    api.nvim_set_keymap(
        'n',
        '<leader>fjl',
        '<cmd>lua require("telescope.builtin").symbols{sources = {"julia"}, prompt_title = "Julia symbols"}<CR>',
        opts
    )
    api.nvim_set_keymap(
        'n',
        '<leader>fjm',
        '<cmd>lua require("telescope.builtin").symbols{sources = {"math"}, prompt_title = "Math symbols"}<CR>',
        opts
    )
    api.nvim_set_keymap(
        'n',
        '<leader>fjn',
        '<cmd>lua require("telescope.builtin").symbols{sources = {"nerd"}, prompt_title = "Nerd-fonts symbols"}<CR>',
        opts
    )
    api.nvim_set_keymap(
        'n',
        '<leader>fjt',
        '<cmd>lua require("telescope.builtin").symbols{sources = {"latex"}, prompt_title = "Latex symbols"}<CR>',
        opts
    )
end

function M.spectre()
    api.nvim_set_keymap('n', '<leader>po', '<cmd>lua require("spectre").open()<CR>', opts)
    api.nvim_set_keymap('n', '<leader>pp', '<cmd>lua require("spectre").open_file_search()<CR>', opts)
    api.nvim_set_keymap('n', '<leader>pw', '<cmd>lua require("spectre").open_visual({select_word = true})<CR>', opts)
    api.nvim_set_keymap('x', '<leader>p', ':lua require("spectre").open_visual()<CR>', opts)
end

function M.persistence()
    api.nvim_set_keymap('n', '<leader>ss', '<cmd>lua require("persistence").save()<CR>', opts)
    api.nvim_set_keymap('n', '<leader>sd', '<cmd>lua require("persistence").stop()<CR>', opts)
    api.nvim_set_keymap('n', '<leader>sl', '<cmd>lua require("persistence").load({last = true})<CR>', opts)
    api.nvim_set_keymap('n', '<leader>sr', '<cmd>lua require("persistence").load()<CR>', opts)
end

return M
