---@param picker string
---@param opts? table
local function pick(picker, opts)
  opts = opts or {}

  return function()
    require('fzf-lua')[picker](opts)
  end
end

return {
  'fzf-lua',
  cmd = 'FzfLua',
  keys = {
    -- Find.
    {
      '<LEADER>fb',
      pick('buffers', { sort_mru = true, sort_lastused = true }),
      desc = 'buffers',
    },
    { '<LEADER>ff', pick('files'), desc = 'find files (root dir)' },
    {
      '<LEADER>fF',
      pick('files', { root = false }),
      desc = 'find files (cwd)',
    },
    { '<LEADER>fg', pick('git_files'), desc = 'find files (git)' },
    { '<LEADER>fr', pick('oldfiles'), desc = 'recent' },
    {
      '<LEADER>fR',
      pick('oldfiles', { cwd = vim.uv.cwd() }),
      desc = 'recent (cwd)',
    },

    -- Git.
    { '<LEADER>gc', pick('git_commits'), desc = 'commits' },
    { '<LEADER>gs', pick('git_status'), desc = 'status' },

    -- Search.
    { '<LEADER>sa', pick('autocmds'), desc = 'auto-commands' },
    { '<LEADER>sb', pick('grep_curbuf'), desc = 'buffer' },
    { '<LEADER>sc', pick('command_history'), desc = 'command history' },
    { '<LEADER>sC', pick('commands'), desc = 'commands' },
    {
      '<LEADER>sd',
      pick('diagnostics_document'),
      desc = 'document diagnostics',
    },
    {
      '<LEADER>sD',
      pick('diagnostics_workspace'),
      desc = 'workspace diagnostics',
    },
    { '<LEADER>sg', pick('live_grep'), desc = 'grep (root dir)' },
    { '<LEADER>sG', pick('live_grep', { root = false }), desc = 'grep (cwd)' },
    { '<LEADER>sh', pick('help_tags'), desc = 'help pages' },
    { '<LEADER>sH', pick('highlights'), desc = 'search highlight groups' },
    { '<LEADER>sj', pick('jumps'), desc = 'jumplist' },
    { '<LEADER>sk', pick('keymaps'), desc = 'keymaps' },
    { '<LEADER>sl', pick('loclist'), desc = 'location list' },
    { '<LEADER>sm', pick('marks'), desc = 'jump to mark' },
    { '<LEADER>sM', pick('man_pages'), desc = 'man pages' },
    { '<LEADER>sq', pick('quickfix'), desc = 'quickfix list' },
    { '<LEADER>sR', pick('resume'), desc = 'resume last picker' },
    { '<LEADER>sw', pick('grep_cword'), desc = 'word under cursor (root dir)' },
    {
      '<LEADER>sw',
      pick('grep_visual'),
      mode = 'v',
      desc = 'selection (root dir)',
    },
    {
      '<LEADER>sW',
      pick('grep_cword', { root = false }),
      desc = 'word under cursor (cwd)',
    },
    {
      '<LEADER>sW',
      pick('grep_visual', { root = false }),
      mode = 'v',
      desc = 'selection (cwd)',
    },
    { '<LEADER>s"', pick('registers'), desc = 'registers' },

    -- Misc.
    { '<LEADER>uC', pick('colorschemes'), desc = 'colorschemes' },
    { '<LEADER><SPACE>', pick('files'), desc = 'find files (root dir)' },
    {
      '<LEADER>,',
      pick('buffers', { sort_mru = true, sort_lastused = true }),
      desc = 'switch buffer',
    },
    { '<LEADER>/', pick('live_grep'), desc = 'grep (root dir)' },
    { '<LEADER>:', pick('command_history'), desc = 'command history' },
  },
  before_all = function()
    vim.ui.select = function(...)
      require('lz.n').trigger_load('fzf-lua')

      require('fzf-lua').register_ui_select(function(fzf_opts, items)
        return vim.tbl_deep_extend('force', fzf_opts, {
          prompt = ' ',
          winopts = {
            title = ' '
              .. vim.trim((fzf_opts.prompt or 'Select'):gsub('%s*:%s*$', ''))
              .. ' ',
            title_pos = 'center',
          },
        }, fzf_opts.kind == 'codeaction' and {
          winopts = {
            layout = 'vertical',
            height = math.floor(
              math.min(vim.o.lines * 0.8 - 16, #items + 2) + 0.5
            ) + 16,
            preview = not vim.tbl_isempty(
                  vim.lsp.get_clients({ bufnr = 0, name = 'vtsls' })
                )
                and {
                  layout = 'vertical',
                  vertical = 'down:15,border-top',
                  hidden = 'hidden',
                }
              or {
                layout = 'vertical',
                vertical = 'down:15,border-top',
              },
          },
        } or {
          winopts = {
            width = 0.5,
            height = math.floor(math.min(vim.o.lines * 0.8, #items + 2) + 0.5),
          },
        })
      end)

      return vim.ui.select(...)
    end
  end,
  after = function()
    local config = require('fzf-lua.config')
    local actions = require('fzf-lua.actions')

    -- quickfix
    config.defaults.keymap.fzf['ctrl-q'] = 'select-all+accept'
    config.defaults.keymap.fzf['ctrl-u'] = 'half-page-up'
    config.defaults.keymap.fzf['ctrl-d'] = 'half-page-down'
    config.defaults.keymap.fzf['ctrl-x'] = 'jump'
    config.defaults.keymap.fzf['ctrl-f'] = 'preview-page-down'
    config.defaults.keymap.fzf['ctrl-b'] = 'preview-page-up'
    config.defaults.keymap.builtin['<c-f>'] = 'preview-page-down'
    config.defaults.keymap.builtin['<c-b>'] = 'preview-page-up'

    -- trouble.nvim
    local has_trouble, _ = pcall(require, 'trouble')
    if has_trouble then
      config.defaults.actions.files['ctrl-t'] =
        require('trouble.sources.fzf').actions.open
    end

    local img_previewer = { 'chafa', '{file}', '--format=symbols' }

    local opts = {
      -- Base profile.
      'default-title',

      fzf_colors = true,
      fzf_opts = {
        ['--no-scrollbar'] = true,
      },

      defaults = {
        formatter = 'path.dirname_first',
      },

      previewers = {
        builtin = {
          extensions = {
            ['png'] = img_previewer,
            ['jpg'] = img_previewer,
            ['jpeg'] = img_previewer,
            ['gif'] = img_previewer,
            ['webp'] = img_previewer,
          },
        },
      },

      winopts = {
        width = 0.8,
        height = 0.8,
        row = 0.5,
        col = 0.5,
        preview = {
          scrollchars = { '┃', '' },
        },
      },

      files = {
        cwd_prompt = false,
        actions = {
          ['alt-i'] = { actions.toggle_ignore },
          ['alt-h'] = { actions.toggle_hidden },
        },
      },

      grep = {
        actions = {
          ['alt-i'] = { actions.toggle_ignore },
          ['alt-h'] = { actions.toggle_hidden },
        },
      },

      lsp = {
        symbols = {
          symbol_hl = function(s)
            return 'TroubleIcon' .. s
          end,
          symbol_fmt = function(s)
            return s:lower() .. '\t'
          end,
          child_prefix = false,
        },
        code_actions = {
          previewer = 'codeaction_native',
        },
      },
    }

    -- Use the same prompt for all pickers for profile 'default-title'.
    local function fix(table)
      table.prompt = table.prompt ~= nil and ' ' or nil

      -- Recurse into subtables.
      for _, value in pairs(table) do
        if type(value) == 'table' then
          fix(value)
        end
      end

      return table
    end

    opts = vim.tbl_deep_extend(
      'force',
      fix(require('fzf-lua.profiles.default-title')),
      opts
    )

    -- Don't let fzf-lua apply the profile as we've already done so above.
    opts[1] = nil

    require('fzf-lua').setup(opts)

    -- LSP keybinds.
    MarleyVim.lsp.on_attach(function(client)
      local set = vim.keymap.set

      local pickOpts =
        { jump_to_single_result = true, ignore_current_line = true }

      set(
        'n',
        'gI',
        pick('lsp_implementations', pickOpts),
        { desc = 'implementation' }
      )
      set(
        'n',
        'gr',
        pick('lsp_references', pickOpts),
        { desc = 'references', nowait = true }
      )
      set(
        'n',
        'gy',
        pick('lsp_typedefs', pickOpts),
        { desc = 't[y]pe definition' }
      )

      if client.supports_method('textDocument/definition') then
        set(
          'n',
          'gd',
          pick('lsp_definitions', pickOpts),
          { desc = 'definition' }
        )
      end
    end)
  end,
}