local bubblewrap = require('wowless.bubblewrap')
local util = require('wowless.util')

return function(datalua, funcheck, log, sqls)
  return function(modules)
    log(1, 'loading functions')

    local function mkfn(fname, apicfg)
      local incheck = apicfg.inputs and funcheck.makeCheckInputs(fname, apicfg)
      local outcheck = apicfg.outputs and funcheck.makeCheckOutputs(fname, apicfg)
      local src = apicfg.src or fname
      local mkbasefn = setfenv(assert(loadstring_untainted(apicfg.impl, src), fname), _G)
      local args = {}
      for _, m in ipairs(apicfg.modules or {}) do
        table.insert(args, (assert(modules[m], 'unknown module ' .. m)))
      end
      for _, sql in ipairs(apicfg.sqls or {}) do
        table.insert(args, sqls[sql])
      end
      local basefn = mkbasefn(unpack(args))
      if not incheck and not outcheck then
        return basefn
      elseif incheck and not outcheck then
        return function(...)
          return basefn(incheck(...))
        end
      elseif not incheck and outcheck then
        return function(...)
          return outcheck(basefn(...))
        end
      else
        return function(...)
          return outcheck(basefn(incheck(...)))
        end
      end
    end

    local fns = {}
    for fn, apicfg in pairs(datalua.apis) do
      if apicfg.stdlib then
        local v = assert(util.tget(_G, fn))
        util.tset(fns, fn, v)
      else
        local v = mkfn(fn, apicfg)
        util.tset(fns, fn, bubblewrap(v))
      end
    end
    log(1, 'functions loaded')
    return fns
  end
end
