{ modulesPath, lib, pkgs, ... }:

let
  inherit (lib.mod) ctrl localLeader Bs;
  inherit (lib.nix2lua) pipe1 require call0 nf var;
in
{
  imports = [
    "${modulesPath}/profiles/base.nix"
    "${modulesPath}/profiles/recommended-plugins.nix"
    ./keymaps.nix
    ./snippets.nix
    ./configs
    ./plugins
  ];

  vim.opt = {
    list = true;
    formatoptions = "roqnlj";
  };

  buffer.filetype = {
    text-options = {
      pattern = [ "txt" "markdown" "mail" "man" ];
      opt = { formatoptions = "roqwnjp"; };
    };
  };

  filetype.detect = {
    d2 = "*.d2";
    nickel = "*.ncl";
    psql = "*.psql";
    sql = "*.pgsql";
  };

  # Enable fast navigation between windows
  vim.keymap.set = map (k: { mode = "n"; lhs = ctrl k; rhs = "${ctrl "w"}${k}"; }) [ "h" "l" "j" "k" ];

  plugin.nvim-web-devicons.enable = true;
  plugin.oil-nvim = {
    enable = true;
    name = "oil";
    setupSettings = {
      columns = [ "icon" ];
    };
  };

  plugin.nvim-surround = {
    enable = true;
    setupSettings = { };
  };

  plugin.nvim-treesitter-textobjects.enable = false;

  plugins.style.nvim-treesitter = {
    extraGrammars = {
      tree-sitter-d2 = rec {
        language = "d2";
        version = "1e6d8ca3d85c0031ff010759bb60804dd47b95f2";
        src = pkgs.fetchFromGitea {
          domain = "git.pleshevski.ru";
          owner = "pleshevskiy";
          repo = "tree-sitter-d2";
          rev = version;
          sha256 = "sha256-ld9zlJ7tXl/SyrHJXwPKviDHePbw/jhI9WPT3aNntt8=";
        };
      };
    };

    # Source: https://github.com/DariusCorvus/tree-sitter-language-injection.nvim/blob/main/lua/tree-sitter-language-injection/init.lua
    extraQueries =
      let
        lang = "sql";
        langMatch = ''^//+[ \t]*${lang}[ \t]*|^/[*]+[ \t]*${lang}[ \t]*[*]+/$'';
        javascriptInjection = ''
          ((comment) @comment .
           ([ (string(string_fragment) @injection.content)
              (template_string(string_fragment) @injection.content)
             ] @injection.content
             )
            (#match? @comment "${langMatch}")
            (#set! injection.language "${lang}")
           )
        '';
      in
      {
        javascript.injections = javascriptInjection;
        typescript.injections = javascriptInjection;
      };

    settings = {
      incremental_selection = {
        enable = true;
        keymaps = {
          init_selection = ctrl "s";
          node_incremental = ctrl "s";
          scope_incremental = "grs";
          node_decremental = Bs;
        };
      };
      textobjects =
        let
          inner = v: "${v}.inner";
          outer = v: "${v}.outer";
          any' = v: "${v}.*";

          # 1  @assignment.inner
          # 2  @assignment.lhs
          # 3  @assignment.outer
          # 4  @assignment.rhs
          ass = "@assignment";
          #-5  @attribute.inner
          #-6  @attribute.outer
          att = "@attribute";
          # 7  @block.inner
          # 8  @block.outer
          blo = "@block";
          # 9  @call.inner
          # 10 @call.outer
          cal = "@call";
          # 11 @class.inner
          # 12 @class.outer
          cla = "@class";
          #-13 @comment.inner
          # 14 @comment.outer
          com = "@comment";
          # 15 @conditional.inner
          # 16 @conditional.outer
          con = "@conditional";
          #-17 @frame.inner
          #-18 @frame.outer
          fra = "@frame";
          # 19 @function.inner
          # 20 @function.outer
          fun = "@function";
          # 21 @loop.inner
          # 22 @loop.outer
          loo = "@loop";
          # 23 @number.inner
          num = "@number";
          # 24 @parameter.inner
          # 25 @parameter.outer
          par = "@parameter";
          # 26 @regex.inner
          # 27 @regex.outer
          reg = "@regex";
          # 28 @return.inner
          # 29 @return.outer
          ret = "@return";
          #-30 @scopename.inner
          # 31 @statement.outer
          sta = "@statement";
        in
        {
          select = {
            enable = true;
            lookahead = true;
            selection_modes = {
              "@parameter.outer" = "v"; # charwise
              "@function.outer" = "V"; # linewise
              "@class.outer" = ctrl "v"; # blockwise
            };
          };
          swap = {
            enable = true;
            swap_next = {
              "${localLeader "a"}" = {
                query = [
                  (inner par)
                  (outer fun)
                ];
              };
              "${localLeader "f"}" = any' fun;
            };
            swap_previous = {
              "${localLeader "A"}" = {
                query = [
                  (inner par)
                  (outer fun)
                ];
              };
              "${localLeader "F"}" = any' fun;
            };
          };
          move = {
            enable = true;
            set_jumps = true;

            goto_next = {
              "]q" = { query = map outer [ cla fun con loo ]; };
            };
            goto_previous = {
              "[q" = { query = map outer [ cla fun con loo ]; };
            };
          };
        };
    };
  };

  plugins.style.neoformat.autoformat = {
    enable = false;
    pattern = [ "*.ts" "*.mts" "*.cts" "*.tsx" "*.rs" "flake.nix" ];
  };

  plugins.navigation = {
    nvim-tree = {
      enable = false;
      settings = {
        renderer = {
          group_empty = true;
          full_name = true;
        };
        tab.sync = {
          open = true;
          close = true;
        };
      };
    };
    telescope.extensions.telescope-live-grep-args-nvim.settings = {
      auto_quoting = true;
      mappings.i = {
        "${ctrl "k"}" = pipe1
          (require "telescope-live-grep-args.actions")
          (call0 "quote_prompt")
        ;
      };
    };
  };

  plugins.snippet.luasnip.settings = {
    ext_opts = [
      (nf (var "luasnip_types.choiceNode") {
        active.virt_text = [ [ "●" "WarningMsg" ] ];
      })
      (nf (var "luasnip_types.insertNode") {
        active.virt_text = [ [ "●" "Title" ] ];
      })
    ];
  };
}