{ config, lib, pkgs, ... }:

let cfg = config.jade.neovim;
in with lib; {
  options.jade.neovim = {
    enable = mkEnableOption "Enable neovim";
  };
  config = mkIf cfg.enable {
    home-manager.users.jade = { pkgs,... } : {
      home.packages = with pkgs; [
        rust-analyzer
        neovide
      ];
      programs.neovim = {
        enable = true;
        defaultEditor = true;
        viAlias = true;
        vimAlias = true;
        vimdiffAlias = true;
        # Plugins {{{
        plugins = with pkgs.vimPlugins; [
          nerdtree-git-plugin
          ctrlp-vim
          vim-devicons
          vim-nix
          vim-pug

          statix
          haskell-tools-nvim

          coc-rust-analyzer
          coc-git
          coc-fzf
          coc-css
          coc-yaml
          coc-json
          coc-html
          coc-emmet
          coc-vimlsp
          coc-tsserver
          {
            plugin = toggleterm-nvim;
            config = ''
                lua require("toggleterm").setup{}
                autocmd TermEnter term://*toggleterm#*
                      \ tnoremap <silent><c-t> <Cmd>exe v:count1 . "ToggleTerm"<CR>

                " By applying the mappings this way you can pass a count to your
                " mapping to open a specific window.
                " For example: 2<C-t> will open terminal 2
                nnoremap <silent><c-t> <Cmd>exe v:count1 . "ToggleTerm direction=float"<CR>
                inoremap <silent><c-t> <Esc><Cmd>exe v:count1 . "ToggleTerm direction=float"<CR>
              '';
          }
          {
            plugin = gruvbox-nvim;
            config = "colorscheme gruvbox";
          }
          { 
            plugin = nerdtree; 
            config = "nmap <C-n> :NERDTreeToggle<CR>";
          }
          {
            plugin = nerdcommenter;
            config = ''
                  vmap ++ <plug>NERDCommenterToggle
                  nmap ++ <plug>NERDCommenterToggle
                '';
          }
        ];
        # }}}
        # Coc {{{
        coc = {
          enable = true;
          settings = {
            rust-analyzer.server.path = "${pkgs.rust-analyzer}/bin/rust-analyzer";
          };
          pluginConfig = ''
            let mapleader = "\<Space>"

            nmap <silent> gd <Plug>(coc-definition)
            nmap <silent> gy <Plug>(coc-type-definition)
            nmap <silent> gi <Plug>(coc-implementation)
            nmap <silent> gr <Plug>(coc-references)
            nnoremap <silent> K :call <SID>show_documentation()<CR>
            nmap gr <Plug>(coc-rename)
            nmap <leader>ac  <Plug>(coc-codeaction)
            nmap <leader>qf  <Plug>(coc-fix-current)

            
            " Use tab for trigger completion with characters ahead and navigate.
            " NOTE: There's always complete item selected by default, you may want to enable
            " no select by `"suggest.noselect": true` in your configuration file.
            " NOTE: Use command ':verbose imap <tab>' to make sure tab is not mapped by
            " other plugin before putting this into your config.
            inoremap <silent><expr> <TAB>
                  \ coc#pum#visible() ? coc#pum#next(1) :
                  \ CheckBackspace() ? "\<Tab>" :
                  \ coc#refresh()
            inoremap <expr><S-TAB> coc#pum#visible() ? coc#pum#prev(1) : "\<C-h>"

            if has('nvim-0.4.0') || has('patch-8.2.0750')
              nnoremap <silent><nowait><expr> <C-f> coc#float#has_scroll() ? coc#float#scroll(1) : "\<C-f>"
              nnoremap <silent><nowait><expr> <C-b> coc#float#has_scroll() ? coc#float#scroll(0) : "\<C-b>"
              inoremap <silent><nowait><expr> <C-f> coc#float#has_scroll() ? "\<c-r>=coc#float#scroll(1)\<cr>" : "\<Right>"
              inoremap <silent><nowait><expr> <C-b> coc#float#has_scroll() ? "\<c-r>=coc#float#scroll(0)\<cr>" : "\<Left>"
              vnoremap <silent><nowait><expr> <C-f> coc#float#has_scroll() ? coc#float#scroll(1) : "\<C-f>"
              vnoremap <silent><nowait><expr> <C-b> coc#float#has_scroll() ? coc#float#scroll(0) : "\<C-b>"
            endif


            " Make <CR> to accept selected completion item or notify coc.nvim to format
            " <C-g>u breaks current undo, please make your own choice.
            inoremap <silent><expr> <CR> coc#pum#visible() ? coc#pum#confirm()
                                          \: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"

            function! CheckBackspace() abort
              let col = col('.') - 1
              return !col || getline('.')[col - 1]  =~# '\s'
            endfunction
                        " Make <CR> to accept selected completion item or notify coc.nvim to format
            " <C-g>u breaks current undo, please make your own choice.
            inoremap <silent><expr> <CR> coc#pum#visible() ? coc#pum#confirm()
                                          \: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"

            function! CheckBackspace() abort
              let col = col('.') - 1
              return !col || getline('.')[col - 1]  =~# '\s'
            endfunction

            " Use <c-space> to trigger completion.
            if has('nvim')
              inoremap <silent><expr> <c-space> coc#refresh()
            else
              inoremap <silent><expr> <c-@> coc#refresh()
            endif
            
            nmap <leader>rn <Plug>(coc-rename)
            '';
        };
        # }}}
        extraConfig = ''
          " neovide
          let g:neovide_refresh_rate_idle=5
          let g:neovide_cursor_animation_length=0.1
          let g:neovide_cursor_trail_size=0.3
          let g:neovide_cursor_vfx_mode="railgun"
          let g:neovide_remember_window_size = v:false

          set guifont=FiraCode\ Nerd\ Font:h11
          set fdm=marker

          nmap H _
          vmap H _

          nmap L $
          vmap L $

          " terminal normal mode
          tnoremap <Esc> <C-\><C-n>

          " j/k move virtual lines (wrapped)
          noremap <silent> <expr> j (v:count == 0 ? 'gj' : 'j')
          noremap <silent> <expr> k (v:count == 0 ? 'gk' : 'k')

          set relativenumber
          set number

          set smarttab
          set cindent
          set tabstop=4
          set shiftwidth=4

          set foldmethod=syntax
        '';
      };
    };
  };
}
