local API = rawget(_G, "LIDCOUNCIL_API")
local INTERNAL_API = type(API) == "table" and type(API.__internal) == "table" and API.__internal or nil
if type(INTERNAL_API) ~= "table" then
  error("LidCouncil missing internal API registry.")
end

INTERNAL_API.LIDCOUNCIL_CreateLootProfileDisplayHelpers_Impl = function(deps)
  deps = type(deps) == "table" and deps or {}

  local TrimText = deps.TrimText
  local PROFILE_CLASS_ICON_TEXTURE = "Interface\\GLUES\\CHARACTERCREATE\\UI-CHARACTERCREATE-CLASSES"

  local function FormatLootProfileRoleLabel(role)
    local resolvedRole = string.upper(TrimText(role))
    if resolvedRole == "MASTER" then
      return "Master"
    end
    if resolvedRole == "COUNCIL" then
      return "Council Member"
    end
    if resolvedRole == "SESSION_HOST" then
      return "Session Host"
    end
    return "Raider"
  end

  local function SortCharacterNames(names)
    table.sort(names, function(left, right)
      local leftText = TrimText(left)
      local rightText = TrimText(right)
      local leftKey = string.lower(leftText)
      local rightKey = string.lower(rightText)
      if leftKey == rightKey then
        return leftText < rightText
      end
      return leftKey < rightKey
    end)
  end

  local function BuildLootProfileRoleListText(entries)
    local masterName = "Unassigned"
    local councilNames = {}
    local raiderNames = {}
    for _, entry in ipairs(entries or {}) do
      local role = string.upper(TrimText(entry and entry.role))
      local character = TrimText(entry and entry.character)
      if character ~= "" then
        if role == "MASTER" then
          masterName = character
        elseif role == "COUNCIL" then
          councilNames[#councilNames + 1] = character
        else
          raiderNames[#raiderNames + 1] = character
        end
      end
    end
    SortCharacterNames(councilNames)
    SortCharacterNames(raiderNames)
    return string.format(
      "Master: %s\nCouncil: %s\nRaiders: %s",
      masterName,
      (#councilNames > 0) and table.concat(councilNames, ", ") or "None",
      (#raiderNames > 0) and table.concat(raiderNames, ", ") or "None"
    )
  end

  local function BuildLootProfileRoleBuckets(entries, profile)
    local buckets = {
      master = "",
      council = {},
      raiders = {},
    }
    local seen = {}

    local function addCharacter(role, character)
      local resolvedRole = string.upper(TrimText(role))
      local resolvedCharacter = TrimText(character)
      if resolvedCharacter == "" then
        return
      end
      local lowerKey = string.lower(resolvedCharacter)
      if resolvedRole == "MASTER" then
        buckets.master = resolvedCharacter
        seen[lowerKey] = true
        return
      end
      if seen[lowerKey] then
        return
      end
      seen[lowerKey] = true
      if resolvedRole == "COUNCIL" then
        buckets.council[#buckets.council + 1] = resolvedCharacter
      else
        buckets.raiders[#buckets.raiders + 1] = resolvedCharacter
      end
    end

    local permissions = type(profile) == "table" and type(profile.meta) == "table" and type(profile.meta.permissions) == "table" and profile.meta.permissions or nil
    if permissions then
      addCharacter("MASTER", permissions.master)
      for memberKey, memberRole in pairs(permissions.members or {}) do
        addCharacter(memberRole, memberKey)
      end
    end

    for _, entry in ipairs(entries or {}) do
      addCharacter(entry and entry.role, entry and entry.character)
    end
    SortCharacterNames(buckets.council)
    SortCharacterNames(buckets.raiders)
    return buckets
  end

  local function GetProfileClassColor(classFile)
    local resolvedClassFile = TrimText(classFile)
    local colorTable = (type(CUSTOM_CLASS_COLORS) == "table" and CUSTOM_CLASS_COLORS[resolvedClassFile])
      or (type(RAID_CLASS_COLORS) == "table" and RAID_CLASS_COLORS[resolvedClassFile])
      or nil
    if colorTable then
      return tonumber(colorTable.r or colorTable[1]) or 0.82,
        tonumber(colorTable.g or colorTable[2]) or 0.82,
        tonumber(colorTable.b or colorTable[3]) or 0.86,
        1
    end
    return 0.82, 0.82, 0.86, 1
  end

  local function BuildProfileClassSummaryLabel(classFile, label, count)
    local resolvedLabel = tostring(label or "Unknown")
    local resolvedCount = tonumber(count) or 0
    local resolvedClassFile = TrimText(classFile)
    local iconText = ""
    local coords = resolvedClassFile ~= "" and type(CLASS_ICON_TCOORDS) == "table" and CLASS_ICON_TCOORDS[resolvedClassFile] or nil
    if type(coords) == "table" then
      iconText = string.format(
        "|T%s:14:14:0:0:256:256:%d:%d:%d:%d|t ",
        PROFILE_CLASS_ICON_TEXTURE,
        math.floor((tonumber(coords[1]) or 0) * 256),
        math.floor((tonumber(coords[2]) or 1) * 256),
        math.floor((tonumber(coords[3]) or 0) * 256),
        math.floor((tonumber(coords[4]) or 1) * 256)
      )
    end
    local r, g, b = GetProfileClassColor(resolvedClassFile)
    local colorHex = string.format("%02x%02x%02x", math.floor((r or 1) * 255), math.floor((g or 1) * 255), math.floor((b or 1) * 255))
    return string.format("%s|cff%s%s|r %d", iconText, colorHex, resolvedLabel, resolvedCount)
  end

  local function FindProfileCharacterMeta(profile, characterKey)
    local resolvedKey = TrimText(characterKey)
    if resolvedKey == "" or type(profile) ~= "table" or type(profile.lootLedgerMeta) ~= "table" then
      return nil
    end
    local direct = profile.lootLedgerMeta[resolvedKey]
    if type(direct) == "table" then
      return direct
    end
    local needle = string.lower(resolvedKey)
    for storedKey, meta in pairs(profile.lootLedgerMeta) do
      if type(meta) == "table" and string.lower(TrimText(storedKey)) == needle then
        return meta
      end
    end
    return nil
  end

  local function FindProfileSessionMember(profile, characterKey)
    local resolvedKey = TrimText(characterKey)
    if resolvedKey == "" or type(profile) ~= "table" or type(profile.sessions) ~= "table" then
      return nil
    end
    local needle = string.lower(resolvedKey)
    for i = #profile.sessions, 1, -1 do
      local session = profile.sessions[i]
      if type(session) == "table" and type(session.members) == "table" then
        local direct = session.members[resolvedKey]
        if type(direct) == "table" then
          return direct
        end
        for memberKey, member in pairs(session.members) do
          local memberName = TrimText(memberKey ~= "" and memberKey or (type(member) == "table" and member.name or ""))
          if memberName ~= "" and string.lower(memberName) == needle and type(member) == "table" then
            return member
          end
        end
      end
    end
    return nil
  end

  local function ResolveProfileMemberDisplay(profile, characterKey)
    local meta = FindProfileCharacterMeta(profile, characterKey)
    local member = FindProfileSessionMember(profile, characterKey)
    return {
      className = TrimText(type(member) == "table" and member.className or (type(meta) == "table" and meta.className) or ""),
      classFile = TrimText(type(member) == "table" and member.classFile or (type(meta) == "table" and meta.classFile) or ""),
      specName = TrimText(type(member) == "table" and member.specName or (type(meta) == "table" and meta.specName) or ""),
      specIcon = TrimText(type(member) == "table" and member.specIcon or (type(meta) == "table" and meta.specIcon) or ""),
    }
  end

  local function ResolveProfileIconData(displayInfo)
    if type(displayInfo) ~= "table" then
      return nil
    end
    local specIcon = TrimText(displayInfo.specIcon)
    if specIcon ~= "" then
      return { texture = specIcon }
    end
    local classFile = TrimText(displayInfo.classFile)
    local coords = classFile ~= "" and type(CLASS_ICON_TCOORDS) == "table" and CLASS_ICON_TCOORDS[classFile] or nil
    if type(coords) == "table" then
      return {
        texture = PROFILE_CLASS_ICON_TEXTURE,
        left = coords[1],
        right = coords[2],
        top = coords[3],
        bottom = coords[4],
      }
    end
    return nil
  end

  local function ApplyProfileIcon(texture, iconData)
    if not texture then
      return
    end
    if type(iconData) ~= "table" or TrimText(iconData.texture) == "" then
      texture:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
      texture:SetTexCoord(0, 1, 0, 1)
      return
    end
    texture:SetTexture(iconData.texture)
    if type(iconData.left) == "number" and type(iconData.right) == "number" and type(iconData.top) == "number" and type(iconData.bottom) == "number" then
      texture:SetTexCoord(iconData.left, iconData.right, iconData.top, iconData.bottom)
    else
      texture:SetTexCoord(0, 1, 0, 1)
    end
  end

  local function BuildProfileInlineIconText(iconData)
    if type(iconData) ~= "table" or TrimText(iconData.texture) == "" then
      return ""
    end
    if type(iconData.left) == "number" and type(iconData.right) == "number" and type(iconData.top) == "number" and type(iconData.bottom) == "number" then
      return string.format(
        "|T%s:14:14:0:0:256:256:%d:%d:%d:%d|t ",
        tostring(iconData.texture),
        math.floor((tonumber(iconData.left) or 0) * 256),
        math.floor((tonumber(iconData.right) or 1) * 256),
        math.floor((tonumber(iconData.top) or 0) * 256),
        math.floor((tonumber(iconData.bottom) or 1) * 256)
      )
    end
    return string.format("|T%s:14:14:0:0|t ", tostring(iconData.texture))
  end

  local function BuildProfileMemberDropdownText(profile, characterKey, roleValue)
    local resolvedCharacter = TrimText(characterKey)
    if resolvedCharacter == "" then
      return "(select character)"
    end
    local display = ResolveProfileMemberDisplay(profile, resolvedCharacter)
    local iconText = BuildProfileInlineIconText(ResolveProfileIconData(display))
    local roleText = TrimText(roleValue) ~= "" and (" | " .. FormatLootProfileRoleLabel(roleValue)) or ""
    local metaText = ""
    if TrimText(display.specName) ~= "" then
      metaText = " | " .. tostring(display.specName)
    elseif TrimText(display.className) ~= "" then
      metaText = " | " .. tostring(display.className)
    end
    local r, g, b = GetProfileClassColor(display.classFile)
    local colorHex = string.format("%02x%02x%02x", math.floor((r or 1) * 255), math.floor((g or 1) * 255), math.floor((b or 1) * 255))
    return string.format("%s|cff%s%s|r%s%s", iconText, colorHex, resolvedCharacter, roleText, metaText)
  end

  local function BuildProfileClassSummary(profile, characters)
    local counts = {}
    for _, characterKey in ipairs(characters or {}) do
      local display = ResolveProfileMemberDisplay(profile, characterKey)
      local classFile = TrimText(display.classFile)
      local className = TrimText(display.className)
      local bucketKey = classFile ~= "" and classFile or string.lower(className ~= "" and className or "Unknown")
      local label = className ~= "" and className or (classFile ~= "" and classFile:gsub("^%l", string.upper):gsub("_", " ") or "Unknown")
      local info = counts[bucketKey]
      if not info then
        info = {
          classFile = classFile,
          label = label,
          count = 0,
        }
        counts[bucketKey] = info
      end
      info.count = info.count + 1
    end

    local entries = {}
    for _, info in pairs(counts) do
      entries[#entries + 1] = info
    end
    table.sort(entries, function(a, b)
      if tonumber(a.count) == tonumber(b.count) then
        return string.lower(tostring(a.label or "")) < string.lower(tostring(b.label or ""))
      end
      return tonumber(a.count) > tonumber(b.count)
    end)

    if #entries == 0 then
      return "No class data yet."
    end

    local parts = {}
    for _, info in ipairs(entries) do
      parts[#parts + 1] = BuildProfileClassSummaryLabel(info.classFile, info.label, info.count)
    end
    return table.concat(parts, " | ")
  end

  local function ResolveRaidPreviewTexture(instanceID)
    local resolvedInstanceID = tonumber(instanceID)
    if not resolvedInstanceID or type(EJ_GetInstanceInfo) ~= "function" then
      return nil
    end

    local ok, _, _, bgImage, buttonImage1, loreImage, buttonImage2 = pcall(EJ_GetInstanceInfo, resolvedInstanceID)
    if not ok then
      return nil
    end

    local candidates = { loreImage, bgImage, buttonImage1, buttonImage2 }
    for _, value in ipairs(candidates) do
      if (type(value) == "number" and value > 0) or (type(value) == "string" and value ~= "") then
        return value
      end
    end
    return nil
  end

  return {
    FormatLootProfileRoleLabel = FormatLootProfileRoleLabel,
    BuildLootProfileRoleListText = BuildLootProfileRoleListText,
    BuildLootProfileRoleBuckets = BuildLootProfileRoleBuckets,
    GetProfileClassColor = GetProfileClassColor,
    ResolveProfileMemberDisplay = ResolveProfileMemberDisplay,
    ResolveProfileIconData = ResolveProfileIconData,
    ApplyProfileIcon = ApplyProfileIcon,
    BuildProfileClassSummary = BuildProfileClassSummary,
    BuildProfileMemberDropdownText = BuildProfileMemberDropdownText,
    ResolveRaidPreviewTexture = ResolveRaidPreviewTexture,
  }
end
