{ config, lib, ... }:

with lib.nix2lua;
let
  inherit (lib.mod) space cmd leader localLeader ctrl;
  gs = config.plugin.gitsigns-nvim.varName;
in
{
  input = {
    leader = lib.mkDefault ",";
    localLeader = lib.mkDefault "'";
  };

  plugins.gitsigns.keymap.set = [
    rec {
      mode = "n";
      lhs = "]h";
      rhs = lambda0 (ifelse (var "vim.wo.diff")
        (call1 "vim.cmd.normal" [ lhs (nf "bang" true) ])
        (call1 "${gs}.nav_hunk" "next")
      );
    }
    rec {
      mode = "n";
      lhs = "[h";
      rhs = lambda0 (ifelse (var "vim.wo.diff")
        (call1 "vim.cmd.normal" [ lhs (nf "bang" true) ])
        (call1 "${gs}.nav_hunk" "prev")
      );
    }
    { mode = "n"; lhs = localLeader "gs"; rhs = raw "${gs}.stage_hunk"; }
    { mode = "n"; lhs = localLeader "gS"; rhs = raw "${gs}.stage_buffer"; }
    { mode = "n"; lhs = localLeader "gr"; rhs = raw "${gs}.reset_hunk"; }
    { mode = "n"; lhs = localLeader "gR"; rhs = raw "${gs}.reset_buffer"; }
    { mode = "n"; lhs = localLeader "gu"; rhs = raw "${gs}.undo_stage_hunk"; }
    { mode = "n"; lhs = localLeader "gp"; rhs = raw "${gs}.preview_hunk"; }
    { mode = "n"; lhs = localLeader "gb"; rhs = lambda0 (call "${gs}.blame_line" { full = true; }); }
    { mode = "n"; lhs = localLeader "gd"; rhs = raw "${gs}.diffthis"; }
    { mode = "n"; lhs = localLeader "gD"; rhs = lambda0 (call "${gs}.diffthis" "~"); }
    { mode = "n"; lhs = localLeader "gtb"; rhs = raw "${gs}.toggle_current_line_blame"; }
    { mode = "n"; lhs = localLeader "gtd"; rhs = raw "${gs}.toggle_deleted"; }
  ];

  plugins.navigation.hop-nvim.keymap.set = { after, before }: [
    { lhs = space "c"; rhs = cmd "HopChar1"; }
    { lhs = space "w"; rhs = cmd "HopWord"; }
    { lhs = space "p"; rhs = cmd "HopPattern"; }
  ];


  plugins.language-server.lspconfig.keymap.set = [
    { mode = "n"; lhs = "gD"; rhs = raw "vim.lsp.buf.declaration"; }
    { mode = "n"; lhs = "gd"; rhs = raw "vim.lsp.buf.definition"; }
    { mode = "n"; lhs = "K"; rhs = raw "vim.lsp.buf.hover"; }
    { mode = "n"; lhs = "gi"; rhs = raw "vim.lsp.buf.implementation"; }
    { mode = "n"; lhs = "gr"; rhs = raw "vim.lsp.buf.references"; }
    { mode = "n"; lhs = "gy"; rhs = raw "vim.lsp.buf.type_definition"; }
    { mode = "n"; lhs = localLeader "sh"; rhs = raw "vim.lsp.buf.signature_help"; }
    { mode = "n"; lhs = localLeader "n"; rhs = raw "vim.lsp.buf.rename"; }
    { mode = [ "n" "v" ]; lhs = localLeader "a"; rhs = raw "vim.lsp.buf.code_action"; }
  ];

  vim.keymap.set = lib.optionals config.plugins.language-server.lspconfig.enable [
    { mode = "n"; lhs = localLeader "df"; rhs = raw "vim.diagnostic.open_float"; }
    { mode = "n"; lhs = "[d"; rhs = raw "vim.diagnostic.goto_prev"; }
    { mode = "n"; lhs = "]d"; rhs = raw "vim.diagnostic.goto_next"; }
    { mode = "n"; lhs = localLeader "dl"; rhs = raw "vim.diagnostic.setloclist"; }
  ] ++ lib.optionals config.plugins.navigation.telescope.enable (
    [
      { mode = "n"; lhs = space "f"; rhs = cmd "Telescope find_files"; }
      { mode = "n"; lhs = space "b"; rhs = cmd "Telescope buffers"; }
      { mode = "n"; lhs = space "?"; rhs = cmd "Telescope help_tags"; }
    ] ++ lib.optionals (config.plugins.navigation.telescope.extensions ? telescope-live-grep-args-nvim) [
      {
        mode = "n";
        lhs = space "g";
        rhs = lambda0 (pipe [
          config.plugin.telescope-nvim.var
          "extensions"
          "live_grep_args"
          (call0 "live_grep_args")
        ]);
      }
    ]
  ) ++ lib.optionals config.plugins.snippet.luasnip.enable (
    let
      ls = pipe1 config.plugin.luasnip.var;
      jump = dir: (if' (ls (call "locally_jumpable" dir)) (ls (call "jump" dir)));
    in
    [
      { mode = "i"; lhs = ctrl "K"; rhs = lambda0 (ls (call0 "expand")); silent = true; }
      { mode = [ "i" "s" ]; lhs = ctrl "L"; rhs = lambda0 (jump 1); silent = true; }
      { mode = [ "i" "s" ]; lhs = ctrl "H"; rhs = lambda0 (jump (-1)); silent = true; }
      {
        mode = [ "i" "s" ];
        lhs = ctrl "E";
        rhs = lambda0 (if' (ls (call0 "choice_active")) (ls (call "change_choice" 1)));
        silent = true;
      }
    ]
  ) ++ lib.optionals config.plugin.oil-nvim.enable [
    { mode = "n"; lhs = "-"; rhs = cmd "Oil"; }
  ];
}