function TABLE_CONTAINS(tbl, x)
  local found = false
  for _, v in pairs(tbl) do
    if v == x then
      found = true
    end
  end
  return found
end

local icons = vim.g.pcode_icons.folding

local M = {}

if vim.g.pcode_nvimufo then
  M.ufo = {
    "kevinhwang91/nvim-ufo",
    dependencies = {
      "kevinhwang91/promise-async",
      {
        "luukvbaal/statuscol.nvim",
        config = function()
          local builtin = require "statuscol.builtin"
          require("statuscol").setup {
            setopt = true,
            relculright = true,
            segments = {
              { text = { "%s" }, click = "v:lua.ScSa" },
              {
                text = { builtin.foldfunc },
                condition = { builtin.not_empty, true, builtin.not_empty },
                click = "v:lua.ScFa",
              },
              { text = { builtin.lnumfunc, " " }, click = "v:lua.ScLa" },
            },
          }
        end,
      },
    },
    enabled = true,
    lazy = true,
    event = "VeryLazy",
    config = function()
      vim.o.foldcolumn = "1" -- '0' is not bad
      vim.o.foldlevel = 99 -- Using ufo provider need a large value, feel free to decrease the value
      vim.o.foldlevelstart = 99
      vim.o.foldenable = true
      -- vim.o.fillchars = [[eob: ,fold: ,foldopen:,foldsep: ,foldclose:]]
      -- vim.o.fillchars = [[eob: ,fold: ,foldopen:,foldsep: ,foldclose:]]
      -- vim.o.fillchars = [[eob: ,fold: ,foldopen:,foldsep:│,foldclose:]]
      -- vim.o.fillchars = [[eob: ,fold: ,foldopen:,foldsep:│,foldclose:]]
      -- vim.o.fillchars = [[eob: ,fold: ,foldopen:󰛲,foldsep:│,foldclose:󰜄]]
      -- vim.o.fillchars = [[eob: ,fold: ,foldopen:,foldsep:│,foldclose:]]
      -- vim.o.fillchars = [[eob: ,fold: ,foldopen:▾,foldsep:│,foldclose:▸]]
      vim.opt.fillchars = {
        vert = icons.vert,
        fold = icons.fold,
        eob = icons.eob,
        diff = icons.diff,
        msgsep = icons.msgsep,
        foldopen = icons.foldopen,
        foldsep = icons.foldsep,
        foldclose = icons.foldclose,
      }
      -- these are "extra", change them as you like
      vim.keymap.set("n", "zR", require("ufo").openAllFolds)
      vim.keymap.set("n", "zM", require("ufo").closeAllFolds)
      vim.cmd("highlight FoldColumn guifg=" .. vim.fn.synIDattr(vim.fn.synIDtrans(vim.fn.hlID "Comment"), "fg"))
      -- start ini bagian code support comment dan import
      local ftMap = {
        vim = "indent",
        python = { "indent" },
        git = "",
      }

      local function customizeSelector(bufnr)
        local function handleFallbackException(err, providerName)
          if type(err) == "string" and err:match "UfoFallbackException" then
            return require("ufo").getFolds(bufnr, providerName)
          else
            return require("promise").reject(err)
          end
        end

        return require("ufo")
          .getFolds(bufnr, "lsp")
          :catch(function(err)
            return handleFallbackException(err, "treesitter")
          end)
          :catch(function(err)
            return handleFallbackException(err, "indent")
          end)
      end

      require("ufo").setup {
        open_fold_hl_timeout = 150,
        close_fold_kinds_for_ft = {
          -- default = { "imports", "comment" },
          -- json = { "array" },
          -- c = { "comment", "region" },
        },
        preview = {
          win_config = {
            border = { "", "─", "", "", "", "─", "", "" },
            winhighlight = "Normal:Folded",
            winblend = 0,
          },
          mappings = {
            scrollU = "<C-u>",
            scrollD = "<C-d>",
            jumpTop = "[",
            jumpBot = "]",
          },
        },
        provider_selector = function(bufnr, filetype, buftype)
          return ftMap[filetype] or customizeSelector
        end,

        fold_virt_text_handler = function(virt_text, lnum, end_lnum, width, truncate)
          local result = {}
          local closed_fold_text = "comments ..." -- Teks yang ingin ditampilkan
          local import_fold_text = "import ..." -- Teks yang ingin ditampilkan
          local is_comment = false -- Variabel untuk mengecek apakah ini komentar
          local is_import = false
          local is_bracket = false

          -- Memeriksa apakah baris awal dari fold adalah komentar
          local start_line = vim.api.nvim_buf_get_lines(0, lnum - 1, lnum, false)[1]
          -- cari comentar dengan awalan /* untuk generaal comment
          if start_line:find "^%s*%/%*" then
            is_comment = true
          -- cara commentar dengan awalan <!-- untuk html
          elseif start_line:find "^%s*<!--" then
            is_comment = true
          -- cari comentar dengan awalan -- untuk lua
          elseif start_line:find "^%s*%-%-" then
            is_comment = true
          end
          -- cek fold yang berawalan import
          if start_line:find "^%s*import" then
            is_import = true
          end
          -- cek fold dengan akhiran {
          if start_line:find "%s*{%s*$" then
            is_bracket = true
          end
          if is_comment then
            local suffix = string.format(" %s ", closed_fold_text)
            local target_width = width - vim.fn.strdisplaywidth(suffix)
            local cur_width = 0
            for _, chunk in ipairs(virt_text) do
              local chunk_text = chunk[1]
              local chunk_width = vim.fn.strdisplaywidth(chunk_text)
              if target_width > cur_width + chunk_width then
                table.insert(result, chunk)
              else
                chunk_text = truncate(chunk_text, target_width - cur_width)
                local hl_group = chunk[2]
                table.insert(result, { chunk_text, hl_group })
                break
              end
              cur_width = cur_width + chunk_width
            end
            -- Menambahkan teks 'Comments ...' ke akhir baris yang dilipat
            table.insert(result, { suffix, "NonText" })
          elseif is_import then
            local suffix = (" 󰁂 %d "):format(end_lnum - lnum)
            local sufWidth = vim.fn.strdisplaywidth(suffix)
            local targetWidth = width - sufWidth
            local curWidth = 0
            for _, chunk in ipairs(virt_text) do
              local chunkText = chunk[1]
              local chunkWidth = vim.fn.strdisplaywidth(chunkText)
              if targetWidth > curWidth + chunkWidth then
                table.insert(result, chunk)
              else
                chunkText = truncate(chunkText, targetWidth - curWidth)
                local hlGroup = chunk[2]
                table.insert(result, { chunkText, hlGroup })
                chunkWidth = vim.fn.strdisplaywidth(chunkText)
                -- str width returned from truncate() may less than 2nd argument, need padding
                if curWidth + chunkWidth < targetWidth then
                  suffix = suffix .. (" "):rep(targetWidth - curWidth - chunkWidth)
                end
                break
              end
              curWidth = curWidth + chunkWidth
            end
            table.insert(result, { " import⋯ ", "NonText" })
            table.insert(result, { suffix, "MoreMsg" })
          else
            local _end = end_lnum - 1
            local final_text = vim.trim(vim.api.nvim_buf_get_text(0, _end, 0, _end, -1, {})[1])
            local suffix = final_text:format(end_lnum - lnum)
            local suffix_width = vim.fn.strdisplaywidth(suffix)
            local target_width = width - suffix_width
            local cur_width = 0
            for _, chunk in ipairs(virt_text) do
              local chunk_text = chunk[1]
              local chunk_width = vim.fn.strdisplaywidth(chunk_text)
              if target_width > cur_width + chunk_width then
                table.insert(result, chunk)
              else
                chunk_text = truncate(chunk_text, target_width - cur_width)
                local hl_group = chunk[2]
                table.insert(result, { chunk_text, hl_group })
                chunk_width = vim.fn.strdisplaywidth(chunk_text)
                -- str width returned from truncate() may less than 2nd argument, need padding
                if cur_width + chunk_width < target_width then
                  suffix = suffix .. (" "):rep(target_width - cur_width - chunk_width)
                end
                break
              end
              cur_width = cur_width + chunk_width
            end
            table.insert(result, { " ⋯ ", "NonText" })
            local l = { "javascriptreact", "typescriptreact" }
            if TABLE_CONTAINS(l, vim.bo.filetype) and not is_bracket then
              table.insert(result, { suffix, "TSPunctBracket" })
            end
          end
          return result
        end,
      }
      -- end bagian code support comment dan import
      vim.api.nvim_create_autocmd("FileType", {
        pattern = {
          "NvimTree",
          "lazy",
          "mason",
        },
        callback = function()
          require("ufo").detach()
          vim.opt_local.foldenable = false
        end,
      })
    end,
  }
else
  M.ufo = {}
end

return M.ufo