local EnsureApiRegistry = rawget(_G, "LIDCOUNCIL_EnsureApiRegistry")
local API, INTERNAL_API
if type(EnsureApiRegistry) == "function" then
  API, INTERNAL_API = EnsureApiRegistry()
else
  API = rawget(_G, "LIDCOUNCIL_API")
  if type(API) ~= "table" then
    API = {}
    _G.LIDCOUNCIL_API = API
  end
  if type(API.__internal) ~= "table" then
    API.__internal = {}
  end
  INTERNAL_API = API.__internal
end

INTERNAL_API.LIDCOUNCIL_CreateLootSessionPayloadCodec_Impl = function()
  local function EscapeField(value)
    local text = tostring(value or "")
    text = text:gsub("%%", "%%25")
    text = text:gsub("\t", "%%09")
    text = text:gsub("\n", "%%0A")
    text = text:gsub("\r", "%%0D")
    return text
  end

  local function UnescapeField(value)
    local text = tostring(value or "")
    text = text:gsub("%%0D", "\r")
    text = text:gsub("%%0A", "\n")
    text = text:gsub("%%09", "\t")
    text = text:gsub("%%25", "%%")
    return text
  end

  local function BuildPayload(kind, ...)
    local fields = { EscapeField(kind) }
    local args = { ... }
    for index = 1, #args do
      fields[#fields + 1] = EscapeField(args[index])
    end
    return table.concat(fields, "\t")
  end

  local function ParsePayload(message)
    local fields = {}
    local startIndex = 1
    local text = tostring(message or "")
    while true do
      local tabIndex = string.find(text, "\t", startIndex, true)
      if not tabIndex then
        fields[#fields + 1] = UnescapeField(text:sub(startIndex))
        break
      end
      fields[#fields + 1] = UnescapeField(text:sub(startIndex, tabIndex - 1))
      startIndex = tabIndex + 1
    end
    return fields
  end

  local function BuildRollOptionFields(options)
    local fields = {}
    local count = 0
    if type(options) == "table" then
      for _, option in ipairs(options) do
        if type(option) == "table" then
          count = count + 1
          local color = option.color or {}
          fields[#fields + 1] = tostring(option.key or "")
          fields[#fields + 1] = tostring(option.label or option.key or "")
          fields[#fields + 1] = tostring(tonumber(color[1]) or 0.82)
          fields[#fields + 1] = tostring(tonumber(color[2]) or 0.82)
          fields[#fields + 1] = tostring(tonumber(color[3]) or 0.86)
          fields[#fields + 1] = tostring(option.icon or "")
        end
      end
    end
    return tostring(count), unpack(fields)
  end

  local function ParseRollOptionFields(fields, startIndex)
    local options = {}
    local count = tonumber(fields[startIndex] or 0) or 0
    local cursor = (tonumber(startIndex) or 1) + 1
    for index = 1, count do
      local key = tostring(fields[cursor] or "")
      local label = tostring(fields[cursor + 1] or key or "")
      local red = tonumber(fields[cursor + 2]) or 0.82
      local green = tonumber(fields[cursor + 3]) or 0.82
      local blue = tonumber(fields[cursor + 4]) or 0.86
      local icon = tostring(fields[cursor + 5] or "")
      cursor = cursor + 6
      if label ~= "" then
        options[#options + 1] = {
          key = key,
          label = label,
          color = { red, green, blue },
          icon = icon ~= "" and icon or nil,
        }
      end
    end
    return options
  end

  return {
    BuildPayload = BuildPayload,
    ParsePayload = ParsePayload,
    BuildRollOptionFields = BuildRollOptionFields,
    ParseRollOptionFields = ParseRollOptionFields,
  }
end
