{ pkgs, ... }:
let
  vp = pkgs.vimPlugins;
in
{
  home.packages = [ pkgs.nodePackages.prettier ];
  programs.neovim = {
    enable = true;

    viAlias = true;
    vimAlias = true;
    vimdiffAlias = true;

    plugins = [
      vp.plenary-nvim

      # # Git related plugins
      # vp.fugitive
      # vp.rhubarb
      vp.gitgutter
      vp.mini-icons

      {
        plugin = vp.alpha-nvim;
        type = "lua";
        config = ''
          require'alpha'.setup(require'alpha.themes.dashboard'.config)
        '';
      }

      # vp.lsp-zero-nvim
      # vp.nvim-cmp
      # vp.cmp-nvim-lsp
      # vp.nvim-lspconfig

      {
        plugin = vp.nvim-surround;
        type = "lua";
        config = ''require("nvim-surround").setup({})'';
      }
      # {
      #   plugin = vp.autoclose-nvim;
      #   type = "lua";
      #   config = ''
      #     require("autoclose").setup({})
      #   '';
      # }

      vp.telescope-fzf-native-nvim
      {
        plugin = vp.telescope-nvim;
        type = "lua";
        config = builtins.readFile ./nvim/telescope-config.lua;
      }

      # Better UI for input and selection
      vp.dressing-nvim

      # # Tree view
      # {
      #   plugin = vp.chadtree;
      #   type = "lua";
      #   config = ''
      #     local chadtree = require("chadtree")
      #
      #     local chadtree_settings = { }
      #     vim.api.nvim_set_var("chadtree_settings", chadtree_settings)
      #
      #     vim.keymap.set({ "n", "v" }, "<leader>v", "<cmd>CHADopen<CR>", { desc = "Toggle file tree" })
      #   '';
      # }

      vp.cmp-buffer # source for text in buffer
      vp.cmp-path # source for file system path
      vp.luasnip

      {
        plugin = vp.luasnip;
        type = "lua";
        config = ''
          local luasnip = require("luasnip")
          local keymap = vim.keymap
          keymap.set({"i"}, "<C-K>", function() luasnip.expand() end, {silent = true})
          keymap.set({"i", "s"}, "<C-l>", function() luasnip.jump( 1) end, {silent = true})
          keymap.set({"i", "s"}, "<C-h>", function() luasnip.jump(-1) end, {silent = true})

          vim.keymap.set({"i", "s"}, "<C-E>", function()
            if luasnip.choice_active() then
              luasnip.change_choice(1)
            end
          end, {silent = true})

          -- loads vscode style snippets from installed plugins (eg. friendly-snippets)
          require("luasnip.loaders.from_vscode").lazy_load()
          require("luasnip.loaders.from_vscode").lazy_load({ paths = "${./nvim/snippets}" })


        '';
      }

      vp.cmp_luasnip
      vp.friendly-snippets
      {
        plugin = vp.nvim-cmp;
        type = "lua";
        config = builtins.readFile ./nvim/nvim-cmp-config.lua;
      }

      # Undo tree
      {
        plugin = vp.undotree;
        type = "lua";
        config = ''
          vim.keymap.set({ "n", "v" }, "<leader>u",
          vim.cmd.UndotreeToggle, { desc = "Toggle undo tree" })
        '';
      }

      vp.markdown-preview-nvim

      # # Detect tabstop and shiftwidth automatically
      # vp.sleuth

      # LSP
      # fidget moving while LSP is working
      {
        plugin = vp.fidget-nvim;
        type = "lua";
        config = ''require("fidget").setup({})'';
      }
      vp.cmp-nvim-lsp
      vp.lsp-format-nvim
      {
        plugin = vp.nvim-lspconfig;
        type = "lua";
        config = builtins.readFile ./nvim/nvim-lspconfig-config.lua;
      }

      # Cool color scheme
      {
        plugin = vp.nightfox-nvim;
        type = "lua";
        config = ''
          vim.cmd [[colorscheme nightfox]]
        '';
      }

      vp.nvim-web-devicons

      # Set lualine as statusline
      {
        plugin = vp.lualine-nvim;
        config = ''
          require("lualine").setup({
            options = {
              icons_enabled = false,
              theme = "nightfox",
              component_separators = "|",
              section_separators = "",
            },
          })
        '';
        type = "lua";
      }

      # # Add indentation guides even on blank lines
      # {
      #   # See `:help ibl`
      #   plugin = vp.indent-blankline-nvim;
      #   config = ''
      #     require("ibl").setup({})
      #   '';
      #   type = "lua";
      # }

      # "gcc" or "gcb" to comment visual regions/lines
      {
        plugin = vp.comment-nvim;
        config = ''
          require("Comment").setup({})
        '';
        type = "lua";
      }

      vp.nvim-treesitter.withAllGrammars
      {
        plugin = vp.nvim-treesitter-textobjects;
        type = "lua";
        config = ''
          require'nvim-treesitter.configs'.setup {
            textobjects = {
              select = {
                enable = true,

                -- Automatically jump forward to textobj, similar to targets.vim
                lookahead = true,

                keymaps = {
                  -- You can use the capture groups defined in textobjects.scm
                  ["af"] = "@function.outer",
                  ["if"] = "@function.inner",
                  ["ac"] = "@class.outer",
                  -- You can optionally set descriptions to the mappings (used in the desc parameter of
                  -- nvim_buf_set_keymap) which plugins like which-key display
                  ["ic"] = { query = "@class.inner", desc = "Select inner part of a class region" },
                  -- You can also use captures from other query groups like `locals.scm`
                  ["as"] = { query = "@scope", query_group = "locals", desc = "Select language scope" },
                },
                -- You can choose the select mode (default is charwise 'v')
                --
                -- Can also be a function which gets passed a table with the keys
                -- * query_string: eg '@function.inner'
                -- * method: eg 'v' or 'o'
                -- and should return the mode ('v', 'V', or '<c-v>') or a table
                -- mapping query_strings to modes.
                selection_modes = {
                  ['@parameter.outer'] = 'v', -- charwise
                  ['@function.outer'] = 'V', -- linewise
                  ['@class.outer'] = '<c-v>', -- blockwise
                },
                -- If you set this to `true` (default is `false`) then any textobject is
                -- extended to include preceding or succeeding whitespace. Succeeding
                -- whitespace has priority in order to act similarly to eg the built-in
                -- `ap`.
                --
                -- Can also be a function which gets passed a table with the keys
                -- * query_string: eg '@function.inner'
                -- * selection_mode: eg 'v'
                -- and should return true or false
                include_surrounding_whitespace = true,
              },
            },
            highlight = {
              enable = true,
              -- Setting this to true will run `:h syntax` and tree-sitter at the same time.
              -- Set this to `true` if you depend on 'syntax' being enabled (like for indentation).
              -- Using this option may slow down your editor, and you may see some duplicate highlights.
              -- Instead of true it can also be a list of languages
              additional_vim_regex_highlighting = false,
            },
            incremental_selection = {
              enable = true,
              keymaps = {
                init_selection = "gnn", -- set to `false` to disable one of the mappings
                node_incremental = "grn",
                scope_incremental = "grc",
                node_decremental = "grm",
              },
            },
            indent = {
              enable = true
            }
          }
        '';
      }

      # Highlighting
      {
        plugin = vp.nvim-colorizer-lua;
        type = "lua";
        config = ''
          local colorizer = require ("colorizer")
          colorizer.setup {
            css = true,
            mode = "background",
            tailwind = true,
          }

          --[[
          require("colorizer").attach_to_buffer(0, { mode = "background", css = true})
          require("colorizer").detach_from_buffer(0, { mode = "virtualtext", css = true})
          ]]--

        '';
      }

      # Formatting
      {
        plugin = vp.conform-nvim;
        type = "lua";
        config = ''
          require("conform").setup({
            formatters_by_ft = {
            -- lua = { "stylua" }
            }
          })
        '';
      }

      {
        plugin = vp.nvim-autopairs;
        type = "lua";
        config = ''
          local npairs = require("nvim-autopairs")
          npairs.setup({check_ts = true})
        '';
      }

      {
        plugin = vp.nvim-ts-autotag;
        type = "lua";
        config = ''
          require('nvim-ts-autotag').setup()

          vim.lsp.handlers['textDocument/publishDiagnostics'] = vim.lsp.with(
            vim.lsp.diagnostic.on_publish_diagnostics, {
                underline = true,
                virtual_text = { spacing = 5 },
                update_in_insert = true,
            }
          )
        '';
      }

      vp.nvim-treesitter-context

      {
        plugin = vp.trouble-nvim;
        type = "lua";
        config = ''
          require('trouble').setup()

          vim.keymap.set({"n"}, "<leader>xx", "<cmd>Trouble diagnostics toggle<cr>")
          vim.keymap.set({"n"}, "<leader>xX", "<cmd>Trouble diagnostics toggle filter.buf=0<cr>")
          vim.keymap.set({"n"}, "<leader>xq", "<cmd>Trouble qflist toggle<cr>")
          vim.keymap.set({"n"}, "<leader>xl", "<cmd>Trouble loclist toggle<cr>")
        '';
      }

      {
        plugin = vp.conform-nvim;
        type = "lua";
        config = ''
          require("conform").setup({
            formatters_by_ft = {
              javascript = { "prettier" },
              typescript = { "prettier" },
              javascriptreact = { "prettier" },
              typescriptreact = { "prettier" },
              svelte = { "prettier" },
              css = { "prettier" },
              html = { "prettier" },
              json = { "prettier" },
              yaml = { "prettier" },
              markdown = { "prettier" },
              graphql = { "prettier" },
            },
            format_on_save = {
              -- These options will be passed to conform.format()
              timeout_ms = 500,
              lsp_format = "fallback",
            },
          })
        '';
      }

      {
        plugin = vp.harpoon2;
        type = "lua";
        config = ''
          local harpoon = require("harpoon")
          harpoon:setup()

          vim.keymap.set("n", "<leader>a", function() harpoon:list():add() end)
          vim.keymap.set("n", "<C-e>", function() harpoon.ui:toggle_quick_menu(harpoon:list()) end)

          vim.keymap.set("n", "<C-h>", function() harpoon:list():select(1) end)
          vim.keymap.set("n", "<C-t>", function() harpoon:list():select(2) end)
          vim.keymap.set("n", "<C-n>", function() harpoon:list():select(3) end)
          vim.keymap.set("n", "<C-s>", function() harpoon:list():select(4) end)

          -- Toggle previous & next buffers stored within Harpoon list
          vim.keymap.set("n", "<C-S-P>", function() harpoon:list():prev() end)
          vim.keymap.set("n", "<C-S-N>", function() harpoon:list():next() end)

          -- basic telescope configuration
          local conf = require("telescope.config").values
          local function toggle_telescope(harpoon_files)
              local file_paths = {}
              for _, item in ipairs(harpoon_files.items) do
                  table.insert(file_paths, item.value)
              end

              require("telescope.pickers").new({}, {
                  prompt_title = "Harpoon",
                  finder = require("telescope.finders").new_table({
                      results = file_paths,
                  }),
                  previewer = conf.file_previewer({}),
                  sorter = conf.generic_sorter({}),
              }):find()
          end

          vim.keymap.set("n", "<C-e>", function() toggle_telescope(harpoon:list()) end,
              { desc = "Open harpoon window" })
        '';
      }

      vp.diffview-nvim
      vp.neogit
    ];

    # settings = { ignorecase = true; };
    # coc.enable = true;
    # extraConfig = ''
    #   let g:airline_powerline_fonts = 1
    # '';
    extraLuaConfig = ''
      -- Setup
      local o = vim.o
      local g = vim.g
      local opt = vim.opt

      -- Font
      o.guifont = "FiraCode Nerd Font Mono 10"

      -- Status bar
      o.laststatus = 3
      o.showmode = false

      -- Clipboard
      -- o.clipboard = "unnamedplus"

      -- Cursor
      o.cursorline = true
      o.cursorlineopt = "number"

      -- Indenting
      o.expandtab = true
      o.shiftwidth = 2
      o.smartindent = true
      o.tabstop = 2
      o.softtabstop = 2

      -- Search
      o.ignorecase = true
      o.smartcase = true

      -- Mouse
      o.mouse = "a"

      -- Numbers
      o.number = true

      -- Obisidan requirement
      o.conceallevel = 1

      -- disable nvim intro
      -- opt.shortmess:append "sI"

      -- Symbols
      o.signcolumn = "yes"
      o.splitbelow = true
      o.splitright = true
      o.timeoutlen = 400
      o.undofile = true

      -- interval for writing swap file to disk, also used by gitsigns
      o.updatetime = 250

      -- go to previous/next line with h,l,left arrow and right arrow
      -- when cursor reaches end/beginning of line
      opt.whichwrap:append "<>[]hl"

      g.mapleader = " "

      -- treesitter folding
      opt.foldmethod = "expr"
      opt.foldexpr = "nvim_treesitter#foldexpr()"
      -- vim.cmd([[ set nofoldenable]])
      opt.foldenable = false

      -- spell checking
      opt.spell = true
      opt.spelllang = "en_us"
    '';
  };
}
