local packer = require('modules.pack')

-- This is recommended when using `luafile <afile>` a lot
-- packer.reset()

return packer.startup(function(use)
    use {'wbthomason/packer.nvim', opt = true}

    ---------------------------------
    -- Plugins used by many others --
    ---------------------------------
    use {'kyazdani42/nvim-web-devicons', module = 'nvim-web-devicons'}
    use {'nvim-lua/plenary.nvim', module = 'plenary'}
    use {'nvim-lua/popup.nvim', module = 'popup'}

    --------
    -- UI --
    --------
    local ui = require('modules.ui')
    use {
        'goolord/alpha-nvim',
        event = 'VimEnter',
        config = ui.dashboard_conf
    }
    use {
        'famiu/feline.nvim',
        event = 'VimEnter',
        wants = 'nvim-web-devicons',
        config = ui.statusline_conf
    }
    use {
        'akinsho/bufferline.nvim',
        event = {'BufRead', 'BufNewFile'},
        config = ui.bufferline_conf
    }
    use {
        'kyazdani42/nvim-tree.lua',
        cmd = 'NvimTreeToggle',
        config = ui.nvimtree_conf
    }
    use {
        'folke/which-key.nvim',
        event = 'VimEnter',
        config = ui.whichkey_conf
    }
    use {
        'lewis6991/gitsigns.nvim',
        event = {'BufRead', 'BufNewFile'},
        wants = 'plenary.nvim',
        config = ui.gitsigns_conf
    }

    ------------
    -- Editor --
    ------------
    local editor = require('modules.editor')
    use {
        'norcalli/nvim-colorizer.lua',
        cmd = 'ColorizerToggle',
        config = editor.colorizer_conf
    }
    use {
        'RRethy/vim-illuminate',
        event = 'CursorHold',
        setup = editor.illuminate_conf
    }
    -- use { -- TODO: config (lua -> fennel) + learn clojure, fennel, guile scheme
    --     'Olical/conjure',
    --     ft = {'clojure', 'fennel', 'scheme'},
    --     requires = {{'Olical/aniseed', config = editor.aniseed_conf}}
    -- }
    use {
        'nvim-treesitter/nvim-treesitter',
        run = ':TSUpdate',
        event = 'BufRead',
        config = editor.treesitter_conf
    }
    use {'p00f/nvim-ts-rainbow', after = 'nvim-treesitter'}
    use {'nvim-treesitter/playground', after = 'nvim-treesitter'}
    use {'romgrk/nvim-treesitter-context', after = 'nvim-treesitter'}
    use {'nvim-treesitter/nvim-treesitter-textobjects', after = 'nvim-treesitter'}
    use {
        'lukas-reineke/indent-blankline.nvim',
        after = 'nvim-treesitter',
        config = editor.blankline_conf
    }
    use {
        'mizlan/iswap.nvim',
        cmd = {'ISwapWith', 'ISwap'},
        wants = 'nvim-treesitter',
        config = editor.iswap_conf
    }
    use {
        'andymass/vim-matchup',
        after = 'nvim-treesitter',
        config = editor.matchup_conf
    }
    use {'machakann/vim-sandwich', keys = 's'} -- TODO: check out surround.nvim
    use {
        'folke/zen-mode.nvim',
        cmd = 'ZenMode',
        wants = 'twilight.nvim',
        requires = {{
            'folke/twilight.nvim',
            cmd = {'Twilight', 'TwilightEnable'},
            config = editor.twilight_conf,
            opt = true
        }},
        config = editor.zenmode_conf
    }
    use {
        'max397574/better-escape.nvim',
        event = 'InsertCharPre',
        config = editor.betterescape_conf
    }
    use {
        'phaazon/hop.nvim',
        cmd = {'HopChar1', 'HopChar2', 'HopWord', 'HopPattern', 'HopLine'},
        config = editor.hop_conf
    }
    use {
        'hrsh7th/vim-eft',
        keys = {
            {'n', 'f'}, {'x', 'f'}, {'n', 'F'}, {'x', 'F'},
            {'n', 't'}, {'x', 't'}, {'n', 'T'}, {'x', 'T'},
            {'n', ';'}, {'x', ';'}
        },
        config = editor.eft_conf
    }
    use {
        'monaqa/dial.nvim',
        keys = {
            {'n', '<C-a>'}, {'v', '<C-a>'}, {'v', 'g<C-a>'},
            {'n', '<C-x>'}, {'v', '<C-x>'}, {'v', 'g<C-x>'}
        },
        config = editor.dial_conf
    }
    use {'junegunn/vim-easy-align', cmd = 'EasyAlign'}
    use {
        'terrortylor/nvim-comment',
        keys = 'gc',
        config = editor.comment_conf
    }
    use {
        'danymat/neogen',
        keys = '<leader>eg',
        wants = 'nvim-treesitter',
        config = editor.neogen_conf
    }
    use {
        'editorconfig/editorconfig-vim',
        event = {'BufRead', 'BufNewFile'}
    }
    use { -- TODO: move to nvim-parinfer (lua)
        'eraserhd/parinfer-rust',
        run = 'cargo build --release',
        ft = {'clojure', 'lisp', 'scheme', 'fennel'}
    }
    use {
        'ahmedkhalf/project.nvim',
        event = 'BufEnter',
        config = editor.project_conf
    }
    use {
        'ruifm/gitlinker.nvim',
        wants = 'plenary.nvim',
        keys = {'<leader>gy', '<leader>gY'},
        config = editor.gitlinker_conf
    }
    use {'jbyuki/venn.nvim', cmd = 'VBox'}

    ---------
    -- LSP --
    ---------
    local lsp = require('modules.lsp')
    use { -- TODO: reconsider lspsaga for actions
        'neovim/nvim-lspconfig',
        event = 'BufReadPre',
        wants = {'lsp_signature.nvim', 'null-ls.nvim'},
        requires = {
            {'ray-x/lsp_signature.nvim', opt = true},
            { -- TODO: scripts to install linters/formatters, config
                'jose-elias-alvarez/null-ls.nvim',
                wants = 'plenary.nvim', opt = true
            }
        },
        config = lsp.lsp_conf
    }
    use {
        'nanotee/sqls.nvim',
        ft = {'sql', 'mysql'},
        wants = 'nvim-lspconfig',
        config = lsp.sqls_conf
    }
    use {
        'kosayoda/nvim-lightbulb',
        after = 'nvim-lspconfig',
        config = lsp.lightbulb_conf
    }
    use {
        'folke/trouble.nvim',
        cmd = {'Trouble', 'TroubleToggle', 'TroubleRefresh'},
        config = lsp.trouble_conf
    }
    -- use { -- FIX: conflict highlights with hop.nvim
    --     'folke/todo-comments.nvim',
    --     wants = 'plenary.nvim',
    --     event = 'BufRead',
    --     config = lsp.comments_conf
    -- }
    use {
        'simrat39/symbols-outline.nvim',
        cmd = {'SymbolsOutline', 'SymbolsOutlineOpen'},
        setup = lsp.outline_conf
    }
    use { -- TODO: config, scripts to install/update dap servers
        'rcarriga/nvim-dap-ui',
        keys = '<leader>d',
        wants = 'nvim-dap',
        requires = {{
            'mfussenegger/nvim-dap',
            config = lsp.dap_conf,
            opt = true
        }},
        config = lsp.dapui_conf
    }

    ----------------
    -- Completion --
    ----------------
    local completion = require('modules.completion')
    use {
        'hrsh7th/nvim-cmp',
        event = 'InsertEnter',
        wants = {'LuaSnip', 'cmp-under-comparator'},
        requires = {
            {
                'L3MON4D3/LuaSnip',
                wants = 'friendly-snippets',
                requires = {{'rafamadriz/friendly-snippets', opt = true}},
                config = completion.snippets_conf,
                opt = true
            },
            {'lukas-reineke/cmp-under-comparator', opt = true}
        },
        config = completion.cmp_conf
    }
    use {'saadparwaiz1/cmp_luasnip', after = 'nvim-cmp'}
    use {'hrsh7th/cmp-path', after = 'nvim-cmp'}
    use {'hrsh7th/cmp-buffer', after = 'nvim-cmp'}
    -- use {'hrsh7th/cmp-calc', after = 'nvim-cmp'}
    use {'uga-rosa/cmp-dictionary', after = 'nvim-cmp'} -- TODO: scripts to curl dicts from aspell.net
    use {'ray-x/cmp-treesitter', after = {'nvim-cmp', 'nvim-treesitter'}}
    use {'hrsh7th/cmp-nvim-lsp', after = {'nvim-cmp', 'nvim-lspconfig'}}
    -- use {
    --     'tzachar/cmp-tabnine',
    --     after = 'nvim-cmp',
    --     run = './install.sh',
    --     config = completion.tabnine_conf
    -- }
    use {'kdheepak/cmp-latex-symbols', after = 'nvim-cmp'}
    -- use {'PaterJason/cmp-conjure', after = {'conjure', 'nvim-cmp'}}
    use {
        'windwp/nvim-autopairs',
        after = 'nvim-cmp',
        config = completion.autopairs_conf
    }
    use {
        'windwp/nvim-ts-autotag',
        ft = {
            'html', 'javascript', 'javascriptreact', 'typescript',
            'typescriptreact', 'vue', 'svelte'
        },
        wants = 'nvim-treesitter',
        config = completion.autotag_conf
    }

    -----------
    -- Tools --
    -----------
    local tools = require('modules.tools')
    use { -- TODO: watch out for fzf-lua
        'nvim-telescope/telescope.nvim',
        cmd = 'Telescope',
        wants = {
            'popup.nvim',
            'plenary.nvim',
            'telescope-symbols.nvim',
            'telescope-project.nvim',
            'telescope-fzf-native.nvim'
        },
        requires = {
            {'nvim-telescope/telescope-symbols.nvim', opt = true},
            {'nvim-telescope/telescope-project.nvim', opt = true},
            {'nvim-telescope/telescope-fzf-native.nvim', run = 'make', opt = true}
        },
        config = tools.telescope_conf
    }
    use { -- TODO: colors + config
        'pwntester/octo.nvim',
        cmd = 'Octo',
        wants = 'telescope.nvim',
        config = tools.octo_conf
    }
    use {
        'TimUntersberger/neogit',
        cmd = 'Neogit',
        wants = {'diffview.nvim', 'plenary.nvim'},
        requires = {{
            'sindrets/diffview.nvim',
            cmd = {
                'DiffviewOpen','DiffviewClose',
                'DiffviewToggleFiles', 'DiffviewFocusFiles'
            },
            config = tools.diffview_conf,
            opt = true
        }},
        config = tools.neogit_conf
    }
    use { -- TODO: replace with code_runner.nvim
        'skywind3000/asynctasks.vim',
        cmd = {
            'AsyncTask',
            'AsyncTaskEdit',
            'AsyncTaskList',
            'AsyncTaskMacro'
        },
        wants = 'asyncrun.vim',
        requires = {{
            'skywind3000/asyncrun.vim',
            setup = tools.asynctasks_conf,
            opt = true
        }}
    }
    use { -- TODO: check out kat0h/bufpreview.vim
        'iamcco/markdown-preview.nvim',
        run = 'cd app && yarn install',
        ft = {'markdown', 'rmd'},
        config = tools.markdown_preview_conf
    }
    use {
        'turbio/bracey.vim',
        run = 'npm install --prefix server',
        cmd = 'Bracey'
    }
    use { -- TODO: check out neorg
        'kristijanhusak/orgmode.nvim',
        ft = 'org',
        config = tools.orgmode_conf
    }
    use {
        'windwp/nvim-spectre',
        keys = '<leader>p',
        wants = 'plenary.nvim',
        config = tools.spectre_conf
    }
    use {
        'echuraev/translate-shell.vim',
        cmd = {'Trans', 'TransSelectDirection'},
        config = tools.translate_conf
    }
    use {
        'mbbill/undotree',
        cmd = 'UndotreeToggle',
        setup = tools.undotree_conf
    }
    use {
        'akinsho/toggleterm.nvim',
        cmd = 'ToggleTerm',
        config = tools.toggleterm_conf
    }
    -- use {
    --     'gelguy/wilder.nvim',
    --     wants = 'cpsm',
    --     requires = {{'nixprime/cpsm', opt = true}},
    --     run = ':UpdateRemotePlugins',
    --     event = 'CmdlineEnter',
    --     config = tools.wilder_conf
    -- }
    use {
        'karb94/neoscroll.nvim',
        event = 'WinScrolled',
        config = tools.neoscroll_conf
    }
    use {
        'michaelb/sniprun',
        run = 'cargo build --release',
        cmd = 'SnipRun',
        config = tools.sniprun_conf
    }
    use {
        'NTBBloodbath/rest.nvim',
        keys = {'<Plug>RestNvim', '<Plug>RestNvimPreview', '<Plug>RestNvimLast'},
        wants = {'plenary.nvim', 'nvim-treesitter'},
        config = tools.rest_conf
    }
    use { -- TODO: check out auto-session + session-lens
        'folke/persistence.nvim',
        event = 'BufReadPre',
        keys = '<leader>s',
        config = tools.session_conf
    }
    use { -- Replace default filetype.vim
        'nathom/filetype.nvim',
        event = {'BufRead', 'BufNewFile'},
        config = tools.filetype_conf
    }
    use {
        'kazhala/close-buffers.nvim',
        cmd = {'BDelete', 'BWipeout'},
        wants = 'bufferline.nvim',
        config = tools.closebuf_conf
    }
    use {
        'sindrets/winshift.nvim',
        cmd = 'WinShift',
        config = tools.winshift_conf
    }
    use {
        'ten3roberts/window-picker.nvim',
        cmd = {'WindowPick', 'WindowSwap', 'WindowSwapStay'},
        config = tools.winpicker_conf
    }
    use {'dstein64/vim-startuptime', cmd = 'StartupTime'} -- Just for benchmarking

    -- TODO: rust-tools.nvim, crates.nvim, go.nvim, clojure-vim/*, nvim-bqf,
    -- nvim-comment-frame, nvim-revJ.lua, nvim-remote-containers, tex.nvim,
    -- telescope-lsp-handlers.nvim, telescope-dap.nvim, fcitx.nvim

    -- Install plugins if missing
    packer.install()
end)
