local M = {}

function M.telescope()
    -- Telescope doesn't set borderchars clockwise so list them again
    -- in the proper order
    local border_styles = {
        single = { '─', '│', '─', '│', '┌', '┐', '┘', '└' },
        rounded = { '─', '│', '─', '│', '╭', '╮', '╯', '╰' },
        double = { '═', '║', '═', '║', '╔', '╗', '╝', '╚' },
    }

    local telescope = require('telescope')

    telescope.setup {
        defaults = {
            prompt_prefix = '   ',
            selection_caret = ' ',
            set_env = { ['COLORTERM'] = 'truecolor' },
            sorting_strategy = 'ascending',
            layout_strategy = 'horizontal',
            layout_config = {
                horizontal = {
                    prompt_position = 'top',
                    preview_width = 0.6,
                },
                width = 0.8,
                height = 0.8,
            },
            borderchars = border_styles[vim.g.border_style],
            file_ignore_patterns = { '.git', '.svn', '.hg', 'node_modules' },
        },
        pickers = {
            find_files = {
                hidden = true,
                follow = true,
            },
            grep_string = {
                opts = '--hidden',
            },
        },
        extensions = {
            file_browser = {
                hidden = true,
            },
            project = {
                base_dirs = { { os.getenv('HOME') .. '/Code', max_depth = 4 } },
                hidden_files = true,
            },
            fzf = {
                fuzzy = true,
                override_generic_sorter = false,
                override_file_sorter = true,
                case_mode = 'smart_case',
            },
        },
    }
    telescope.load_extension('file_browser')
    telescope.load_extension('projects')
    telescope.load_extension('project')
    telescope.load_extension('fzf')
    telescope.load_extension('notify')

    require('user.keymap.plugmap').telescope_symbols()
end

function M.octo()
    require('octo').setup()
end

function M.diffview()
    require('diffview').setup { diff_binaries = true }
end

function M.neogit()
    require('neogit').setup {
        integrations = {
            diffview = true,
        },
    }
end

function M.yabs()
    require('yabs'):setup {
        languages = {
            vim = { tasks = { run = { command = 'source %', type = 'vim' } } },
            lua = { tasks = { run = { command = 'luafile %', type = 'vim' } } },
            fish = { tasks = { run = { command = 'fish %', type = 'shell', output = 'terminal' } } },
            sh = { tasks = { run = { command = 'sh %', type = 'shell', output = 'terminal' } } },
            javascript = { tasks = { run = { command = 'node %', type = 'shell', output = 'terminal' } } },
            python = { tasks = { run = { command = 'python3 %', type = 'shell', output = 'terminal' } } },
        },
        tasks = {
            cmake_init = {
                command = 'mkdir build && cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -S . -B build && ln -sf build/compile_commands.json .',
                type = 'shell',
                output = 'terminal',
            },
            cmake_build = {
                command = 'cmake --build build',
                type = 'shell',
                output = 'terminal',
            },
            meson_init = {
                command = 'mkdir build && meson setup --wipe build && ln -sf build/compile_commands.json .',
                type = 'shell',
                output = 'terminal',
            },
            meson_build = {
                command = 'ninja -C build',
                type = 'shell',
                output = 'terminal',
            },
            run = {
                command = function()
                    return './' .. vim.fn.expand('%:r')
                end,
                type = 'shell',
                output = 'terminal',
            },
            build = {
                command = 'make',
                type = 'shell',
                output = 'terminal',
            },
        },
    }
end

function M.markdown_preview()
    local opts = {
        mkdp_refresh_slow = 1,
        mkdp_filetypes = { 'markdown', 'rmd' },
        -- mkdp_browser = 'qutebrowser',
        mkdp_page_title = '${name}.md',
        mkdp_echo_preview_url = 0,
        mkdp_preview_options = {
            sync_scroll_type = 'middle',
            hide_yaml_meta = 1,
            disable_filename = 1,
        },
        mkdp_highlight_css = vim.fn.stdpath('config') .. '/markdown-highlight.css',
        mkdp_markdown_css = vim.fn.stdpath('config') .. '/markdown-preview.css',
    }

    for key, val in pairs(opts) do
        vim.g[key] = val
    end
end

function M.web_tools()
    require('web-tools').setup {
        keymaps = {
            rename = '',
            repeat_rename = '.',
        },
    }
end

function M.spectre()
    require('spectre').setup()
    require('user.keymap.plugmap').spectre()
end

function M.undotree()
    local opts = {
        undotree_WindowLayout = 2,
        undotree_SplitWidth = 30,
        undotree_DiffpaneHeight = 10,
        undotree_SetFocusWhenToggle = 1,
        undotree_RelativeTimestamp = 1,
    }

    for key, val in pairs(opts) do
        vim.g[key] = val
    end
end

function M.toggleterm()
    require('toggleterm').setup {
        shade_terminals = false,
        float_opts = {
            border = vim.g.border_style,
            -- width = 80,
            -- height = 80,
            winblend = 0,
            highlights = {
                border = 'Normal',
                background = 'NormalFloat',
            },
        },
    }
end

function M.sniprun()
    local c = require('user.themes.' .. vim.g.colors_name .. '.colors')

    require('sniprun').setup {
        display = {
            'Classic',
            -- 'VirtualTextOk',
            -- 'VirtualTextErr',
            -- 'TempFloatingWindow',
            -- 'LongTempFloatingWindow',
            -- 'Terminal',
            'NvimNotify',
            -- 'Api'
        },
        display_options = {
            terminal_width = 45,
            notification_timeout = 2000,
        },
        show_no_output = {
            'Classic',
            'NvimNotify',
            'TempFloatingWindow', --# implies LongTempFloatingWindow, which has no effect on its own
        },
        snipruncolors = {
            SniprunVirtualTextOk = { bg = c.cyan, fg = c.black },
            SniprunFloatingWinOk = { fg = c.cyan },
            SniprunVirtualTextErr = { bg = c.orange, fg = c.black },
            SniprunFloatingWinErr = { fg = c.orange },
        },
        inline_messages = 0,
        borders = vim.g.border_style,
    }
end

function M.rest()
    require('rest-nvim').setup {
        -- Open request results in a horizontal split
        result_split_horizontal = false,
        -- Skip SSL verification, useful for unknown certificates
        skip_ssl_verification = false,
        -- Highlight request on run
        highlight = {
            enabled = true,
            timeout = 150,
        },
        -- Jump to request line on run
        jump_to_request = false,
    }
end

function M.persistence()
    require('persistence').setup {
        dir = vim.fn.expand(vim.fn.stdpath('data') .. '/sessions/'),
        options = { 'buffers', 'curdir', 'tabpages', 'winsize' },
    }

    require('user.keymap.plugmap').persistence()
end

function M.close_buffers()
    require('close_buffers').setup {
        preserve_window_layout = { 'this' },
        next_buffer_cmd = function(windows)
            require('bufferline').cycle(1)
            local bufnr = vim.api.nvim_get_current_buf()

            for _, window in ipairs(windows) do
                vim.api.nvim_win_set_buf(window, bufnr)
            end
        end,
    }
end

function M.winshift()
    require('winshift').setup {
        highlight_moving_win = true, -- Highlight the window being moved
        focused_hl_group = 'Visual', -- The highlight group used for the moving window
        moving_win_options = {
            -- These are local options applied to the moving window while it's
            -- being moved. They are unset when you leave Win-Move mode.
            wrap = false,
            cursorline = false,
            cursorcolumn = false,
            colorcolumn = '',
        },
    }
end

function M.window_picker()
    require('window-picker').setup {
        keys = 'alskdjfhgwoeiruty',
        -- Swap windows by holding shift + letter
        swap_shift = true,
        exclude = { alpha = true },
        -- Flash the cursor line of the newly focused window
        flash_duration = 300,
    }
end

return M
