local utils = {}
local settingsListeners = {}

function utils.onSettingsUpdate(callback)
  table.insert(settingsListeners, callback)
end

function utils.raiseSettingsUpdate(data)
  for i = 1, #settingsListeners do
    settingsListeners[i](data)
  end
end

---@param execCallback fun(cb: function)
---@param completionCallback fun(err: string?, data: table?)?
function utils.whenAll(execCallback, completionCallback, dbg)
  local waiting, resultErr, result, ready, nextIndex = 0, nil, {}, false, 1
  try(function () 
    execCallback(function ()
      waiting = waiting + 1
      if dbg then ac.warn(dbg..': '..waiting) end
      local index = nextIndex
      nextIndex = index + 1
      return function (err, data)
        waiting = waiting - 1
        if err then resultErr = resultErr and resultErr..'\n'..err or err end
        if not resultErr then result[index] = data end
        if ready and waiting == 0 then
          local cc = completionCallback
          if cc then
            completionCallback = nil
            cc(resultErr, not resultErr and result or nil)
          end
        end
      end
    end)
    ready = true
    if waiting == 0 then
      local cc = completionCallback
      if cc then
        completionCallback = nil
        cc(resultErr, not resultErr and result or nil)
      end
    end
  end, function (err)
    local cc = completionCallback
    if cc then
      completionCallback = nil
      cc(err, nil)
    end
  end)
end

---@generic T
---@param fn fun(): T
---@return T?
function utils.tryCreate(obj, fn)
  return try(fn, function (err) ac.error(err) end)
end

---@param obj {index: integer}
---@param err string?
function utils.reportError(obj, err)
  if type(err) == 'string' then
    ac.error(err)
  end
end

return utils

