local function register(ensure_installed)
    for filetype, parser in pairs(ensure_installed) do
        local filetypes = vim.treesitter.language.get_filetypes(parser)
        if not vim.tbl_contains(filetypes, filetype) then
            table.insert(filetypes, filetype)
        end

        -- register and start parsers for filetypes
        vim.treesitter.language.register(parser, filetypes)
    end
end

--- Install and start parsers for nvim-treesitter.
local function install_and_start()
    -- Auto-install and start treesitter parser for any buffer with a registered filetype
    vim.api.nvim_create_autocmd({ "BufWinEnter" }, {
        callback = function(event)
            local bufnr = event.buf
            local filetype = vim.api.nvim_get_option_value("filetype", { buf = bufnr })

            -- Skip if no filetype
            if filetype == "" then
                return
            end

            -- Get parser name based on filetype
            local parser_name = vim.treesitter.language.get_lang(filetype) -- WARNING: might return filetype (not helpful)
            if not parser_name then
                return
            end

            vim.notify(
                vim.inspect("Successfully got parser " .. parser_name .. " for filetype " .. filetype),
                vim.log.levels.DEBUG,
                { title = "core/treesitter" }
            )

            -- Check if parser_name is available in parser configs
            local parser_configs = require("nvim-treesitter.parsers")
            local parser_can_be_used = parser_configs[parser_name]
            if not parser_can_be_used then
                return -- Parser not ailable, skip silently
            end

            local parser_installed = pcall(vim.treesitter.get_parser, bufnr, parser_name)

            -- If not installed, install parser synchronously
            if not parser_installed then
                require("nvim-treesitter").install({ parser_name }):wait(30000) -- main branch syntax
                vim.notify("Installed parser: " .. parser_name, vim.log.levels.INFO, { title = "core/treesitter" })
            end

            -- Check so tree-sitter can see the newly installed parser
            parser_installed = pcall(vim.treesitter.get_parser, bufnr, parser_name)
            if not parser_installed then
                return
            end

            -- Start treesitter for this buffer
            vim.treesitter.start(bufnr, parser_name)
        end,
    })
end

return {
    -- Treesitter
    {
        'nvim-treesitter/nvim-treesitter',
        lazy = false,
        branch = 'main',
        build = ':TSUpdate',
        opts = {
            ensure_installed = { "python", "go", "elixir", "heex", "rust", "gomod", "json", "lua", "yaml", "norg",
                "query", "markdown", "markdown_inline", "gleam", "zig", "odin", "terraform", "hcl" }
        },
        config = function(_, opts)
            -- Register parsers from opts.ensure_installed
            register(opts.ensure_installed)

            -- Create autocmd which installs and starts parsers.
            install_and_start()
        end
    },
    {
      {
        "meanderingprogrammer/treesitter-modules.nvim",
        dependencies = { "nvim-treesitter/nvim-treesitter" },
        opts = {
          incremental_selection = {
            enable = true,
            keymaps = {
              init_selection = "<A-o>",
              node_incremental = "<A-o>",
              scope_incremental = "<A-O>",
              node_decremental = "<A-i>",
            },
          },
        },
      },
    },
}
