_G.LIDCOUNCIL_CreateLootLedgerHelpers_Impl = function(deps)
  deps = type(deps) == "table" and deps or {}

  local TrimText = deps.TrimText
  local ExtractItemID = deps.ExtractItemID
  local EnsureLidTableRows = deps.EnsureLidTableRows
  local NormalizePointMode = deps.NormalizePointMode
  local NormalizeLootRollPointBehavior = deps.NormalizeLootRollPointBehavior
  local GetLootRollPointCounterKey = deps.GetLootRollPointCounterKey
  local NormalizeLootLedgerMainAltRole = deps.NormalizeLootLedgerMainAltRole
  local EnsureLootLedgerMeta = deps.EnsureLootLedgerMeta
  local EnsureLootLedgerMetaEntry = deps.EnsureLootLedgerMetaEntry
  local GetLootProfile = deps.GetLootProfile
  local TouchLootProfile = deps.TouchLootProfile
  local GetLootProfileDomainRevision = deps.GetLootProfileDomainRevision
  local DeepCopy = deps.DeepCopy
  local lootLedgerCharactersCache = {}

  local function NextLootLedgerEntryId(profile)
    profile = type(profile) == "table" and profile or {}
    profile.lootLedgerEntrySerial = math.max(0, tonumber(profile.lootLedgerEntrySerial) or 0) + 1
    return "ledger-" .. tostring(profile.lootLedgerEntrySerial)
  end

  local function RecalculateLootLedgerRowTotal(row)
    row = type(row) == "table" and row or {}
    local total = 0
    for _, item in ipairs(row.items or {}) do
      total = total + (tonumber(type(item) == "table" and item.points) or 0)
    end
    row.totalPoints = total
    return total
  end

  local function CountLootLedgerAwardCounters(items)
    local counters = {
      bis = 0,
      offSpec = 0,
      transmog = 0,
      disenchant = 0,
    }

    for _, item in ipairs(items or {}) do
      if type(item) == "table" then
        local counterKey = string.lower(TrimText(item.awardCounterKey))
        if counterKey == "" then
          local pointBehavior = NormalizeLootRollPointBehavior(item.pointBehavior, item.rollOptionKey, item.rollOptionLabel)
          counterKey = string.lower(TrimText(GetLootRollPointCounterKey(pointBehavior)))
        end

        if counterKey == "bis" then
          counters.bis = counters.bis + 1
        elseif counterKey == "offspec" then
          counters.offSpec = counters.offSpec + 1
        elseif counterKey == "transmog" then
          counters.transmog = counters.transmog + 1
        elseif counterKey == "disenchant" then
          counters.disenchant = counters.disenchant + 1
        end
      end
    end

    return counters
  end

  local function CountLootLedgerItemEntries(items)
    local count = 0
    for _, item in ipairs(items or {}) do
      if type(item) == "table" and item.isManual ~= true then
        count = count + 1
      end
    end
    return count
  end

  local function GetLootProfileRevision(profile)
    if type(GetLootProfileDomainRevision) == "function" then
      return GetLootProfileDomainRevision(profile, "operational")
    end
    if type(profile) ~= "table" then
      return 0
    end
    profile.meta = profile.meta or {}
    return math.max(0, tonumber(profile.meta.revision) or 0)
  end

  local function AddLootLedgerEntry(name, characterKey, itemName, itemLevel, points, note, itemID, itemLink, itemIcon, itemQuality, awardData)
    local profile = GetLootProfile(name)
    local memberKey = TrimText(characterKey)
    local lootName = TrimText(itemName)
    local resolvedItemID = ExtractItemID(itemID or itemLink)
    local resolvedItemLink = TrimText(itemLink)
    local resolvedItemIcon = itemIcon
    local resolvedItemQuality = tonumber(itemQuality)
    local resolvedItemLevel = tonumber(itemLevel)
    local resolvedAwardData = type(awardData) == "table" and awardData or nil

    if lootName == "" and resolvedItemLink ~= "" then
      local linkName = resolvedItemLink:match("%[(.-)%]")
      if linkName then
        lootName = TrimText(linkName)
      end
    end

    local itemInfoSource = resolvedItemLink ~= "" and resolvedItemLink or resolvedItemID
    if itemInfoSource and type(GetItemInfo) == "function" then
      local infoName, infoLink, infoQuality, infoItemLevel, _, _, _, _, _, infoIcon = GetItemInfo(itemInfoSource)
      if lootName == "" then
        lootName = TrimText(infoName)
      end
      if resolvedItemLink == "" then
        resolvedItemLink = TrimText(infoLink)
      end
      if not resolvedItemIcon then
        resolvedItemIcon = infoIcon
      end
      if not resolvedItemQuality then
        resolvedItemQuality = tonumber(infoQuality)
      end
      if not resolvedItemLevel then
        resolvedItemLevel = tonumber(infoItemLevel)
      end
    end

    if memberKey == "" then
      return false, "Character-Realm is required."
    end
    if lootName == "" then
      return false, "Item name is required."
    end

    EnsureLootLedgerMetaEntry(profile, memberKey)
    local ledger = profile.lootLedger
    ledger[memberKey] = ledger[memberKey] or {
      character = memberKey,
      totalPoints = 0,
      items = {},
    }

    local pointsValue = tonumber(points) or 0
    local pointBehavior = resolvedAwardData and NormalizeLootRollPointBehavior(resolvedAwardData.pointBehavior, resolvedAwardData.optionKey, resolvedAwardData.optionLabel) or nil
    local counterKey = resolvedAwardData and TrimText(resolvedAwardData.counterKey) or ""
    local requestedEntryId = resolvedAwardData and TrimText(resolvedAwardData.entryId) or ""
    local requestedEntrySerial = tonumber(requestedEntryId:match("^ledger%-(%d+)$"))
    if requestedEntrySerial then
      profile.lootLedgerEntrySerial = math.max(tonumber(profile.lootLedgerEntrySerial) or 0, requestedEntrySerial)
    end
    local entry = {
      entryId = requestedEntryId ~= "" and requestedEntryId or NextLootLedgerEntryId(profile),
      itemName = lootName,
      itemLevel = resolvedItemLevel,
      points = pointsValue,
      note = TrimText(note),
      itemID = resolvedItemID,
      itemLink = resolvedItemLink ~= "" and resolvedItemLink or nil,
      itemIcon = resolvedItemIcon,
      itemQuality = resolvedItemQuality,
      awardedAt = time and time() or 0,
      pointBehavior = pointBehavior,
      awardCounterKey = counterKey ~= "" and counterKey or (pointBehavior and GetLootRollPointCounterKey(pointBehavior) or nil),
      rollOptionKey = resolvedAwardData and TrimText(resolvedAwardData.optionKey) or nil,
      rollOptionLabel = resolvedAwardData and TrimText(resolvedAwardData.optionLabel) or nil,
      rollOptionColor = resolvedAwardData and DeepCopy(resolvedAwardData.optionColor) or nil,
      rollValue = resolvedAwardData and tonumber(resolvedAwardData.rollValue) or nil,
      sessionId = resolvedAwardData and TrimText(resolvedAwardData.sessionId) or nil,
      grantedBy = resolvedAwardData and TrimText(resolvedAwardData.grantedBy) or nil,
      sourceRequestId = resolvedAwardData and TrimText(resolvedAwardData.sourceRequestId) or nil,
      isManual = resolvedAwardData and resolvedAwardData.isManual == true or false,
    }
    if resolvedAwardData and tonumber(resolvedAwardData.awardedAt) then
      entry.awardedAt = tonumber(resolvedAwardData.awardedAt)
    end
    ledger[memberKey].items[#ledger[memberKey].items + 1] = entry
    RecalculateLootLedgerRowTotal(ledger[memberKey])
    TouchLootProfile(profile)
    return true, entry, ledger[memberKey]
  end

  local function RemoveLootLedgerEntry(name, characterKey, entryId)
    local profile = GetLootProfile(name)
    local memberKey = TrimText(characterKey)
    local resolvedEntryId = TrimText(entryId)
    if memberKey == "" then
      return false, "Character-Realm is required."
    end
    if resolvedEntryId == "" then
      return false, "Ledger entry id is required."
    end

    local ledger = type(profile) == "table" and profile.lootLedger or nil
    local row = type(ledger) == "table" and ledger[memberKey] or nil
    if type(row) ~= "table" or type(row.items) ~= "table" then
      return false, "Ledger row not found."
    end

    for index = #row.items, 1, -1 do
      local item = row.items[index]
      if type(item) == "table" and TrimText(item.entryId) == resolvedEntryId then
        table.remove(row.items, index)
        RecalculateLootLedgerRowTotal(row)
        TouchLootProfile(profile)
        return true, item, row
      end
    end

    return false, "Ledger entry not found."
  end

  local lidLootSetScanTooltip

  local function IsSetPieceItemLink(itemLink)
    local link = TrimText(itemLink)
    if link == "" or type(CreateFrame) ~= "function" or not UIParent then
      return false
    end

    if not lidLootSetScanTooltip then
      lidLootSetScanTooltip = CreateFrame("GameTooltip", "LIDCOUNCIL_SetScanTooltip", UIParent, "GameTooltipTemplate")
      lidLootSetScanTooltip:SetOwner(UIParent, "ANCHOR_NONE")
    end

    lidLootSetScanTooltip:ClearLines()
    if not pcall(lidLootSetScanTooltip.SetHyperlink, lidLootSetScanTooltip, link) then
      return false
    end

    local tooltipName = lidLootSetScanTooltip:GetName()
    for i = 1, (lidLootSetScanTooltip:NumLines() or 0) do
      local left = _G[tooltipName .. "TextLeft" .. tostring(i)]
      local text = left and left:GetText() or nil
      if text and text:match("%(%d+/%d+%)") then
        return true
      end
    end
    return false
  end

  local function ResolveLootPointValue(name, itemName, itemLevel, itemID, itemLink)
    local profile = GetLootProfile(name)
    local resolvedItemID = ExtractItemID(itemID)
    local resolvedName = string.lower(TrimText(itemName))
    local resolvedLevel = tonumber(itemLevel)
    local pointMode = NormalizePointMode(profile.settings and profile.settings.pointMode)
    local rules = profile.settings and profile.settings.pointRules or {}

    if pointMode == "LIDTABLE" then
      local rows = EnsureLidTableRows(profile.settings)
      local isSetPiece = IsSetPieceItemLink(itemLink)
      if resolvedLevel then
        for index, row in ipairs(rows) do
          if tonumber(row.itemLevel) == resolvedLevel then
            local pointsValue = tonumber(row.points) or tonumber(index) or 0
            if isSetPiece and row.setPiecePoints ~= nil then
              pointsValue = tonumber(row.setPiecePoints) or pointsValue
            end
            return pointsValue, {
              mode = "lidtable",
              rowIndex = index,
              itemLevel = tonumber(row.itemLevel),
              points = tonumber(row.points) or tonumber(index) or 0,
              setPiecePoints = tonumber(row.setPiecePoints),
              offSpecPoints = tonumber(row.offSpecPoints),
              transmogPoints = tonumber(row.transmogPoints),
              disenchantPoints = tonumber(row.disenchantPoints),
              matchedSetPiece = isSetPiece and true or false,
            }
          end
        end
      end
      return 0, nil
    end

    if resolvedItemID then
      for _, rule in ipairs(rules) do
        if type(rule) == "table" and rule.mode == "item" and tonumber(rule.itemID) == resolvedItemID then
          return tonumber(rule.points) or 0, DeepCopy(rule)
        end
      end
    end

    if resolvedName ~= "" then
      for _, rule in ipairs(rules) do
        if type(rule) == "table" and rule.mode == "item" then
          if string.lower(TrimText(rule.itemName)) == resolvedName then
            return tonumber(rule.points) or 0, DeepCopy(rule)
          end
        end
      end
    end

    if resolvedLevel then
      for _, rule in ipairs(rules) do
        if type(rule) == "table" and rule.mode == "itemLevel" and tonumber(rule.itemLevel) == resolvedLevel then
          return tonumber(rule.points) or 0, DeepCopy(rule)
        end
      end
    end

    return 0, nil
  end

  local function ResolveSelectionPointBehavior(profile, selection, optionOverrides)
    local selectionTable = type(selection) == "table" and selection or nil
    local explicitBehavior = selectionTable and selectionTable.pointBehavior or nil
    local optionKey = TrimText(selectionTable and (selectionTable.optionKey or selectionTable.key) or "")
    local optionLabel = TrimText(selectionTable and selectionTable.label or "")
    if TrimText(explicitBehavior) ~= "" then
      return NormalizeLootRollPointBehavior(explicitBehavior, optionKey, optionLabel)
    end

    local options = type(optionOverrides) == "table" and optionOverrides or (profile and profile.settings and profile.settings.rollOptions) or nil
    local needleKey = string.lower(optionKey)
    local needleLabel = string.lower(optionLabel)
    for _, option in ipairs(options or {}) do
      local candidateKey = string.lower(TrimText(type(option) == "table" and (option.key or option.label) or ""))
      local candidateLabel = string.lower(TrimText(type(option) == "table" and (option.label or option.key) or ""))
      if (needleKey ~= "" and needleKey == candidateKey) or (needleLabel ~= "" and needleLabel == candidateLabel) then
        return NormalizeLootRollPointBehavior(option.pointBehavior, option.key, option.label)
      end
    end

    return NormalizeLootRollPointBehavior(nil, optionKey, optionLabel)
  end

  local function ResolveLootAwardOutcome(name, itemName, itemLevel, itemID, itemLink, selection, optionOverrides)
    local profile = GetLootProfile(name)
    local basePoints, matchedRule = ResolveLootPointValue(name, itemName, itemLevel, itemID, itemLink)
    local pointBehavior = ResolveSelectionPointBehavior(profile, selection, optionOverrides)
    local pointMode = NormalizePointMode(profile.settings and profile.settings.pointMode)
    local finalPoints = tonumber(basePoints) or 0

    if pointBehavior == "OFFSPEC" then
      if pointMode == "LIDTABLE" then
        finalPoints = tonumber(type(matchedRule) == "table" and matchedRule.offSpecPoints) or 0
      else
        finalPoints = 0
      end
    elseif pointBehavior == "TRANSMOG" then
      if pointMode == "LIDTABLE" then
        finalPoints = tonumber(type(matchedRule) == "table" and matchedRule.transmogPoints) or 0
      else
        finalPoints = 0
      end
    elseif pointBehavior == "DISENCHANT" then
      if pointMode == "LIDTABLE" then
        finalPoints = tonumber(type(matchedRule) == "table" and matchedRule.disenchantPoints) or 0
      else
        finalPoints = 0
      end
    elseif pointBehavior == "NONE" then
      finalPoints = 0
    end

    return tonumber(finalPoints) or 0, {
      mode = pointMode,
      basePoints = tonumber(basePoints) or 0,
      pointBehavior = pointBehavior,
      counterKey = GetLootRollPointCounterKey(pointBehavior),
      optionKey = TrimText(type(selection) == "table" and (selection.optionKey or selection.key) or ""),
      optionLabel = TrimText(type(selection) == "table" and selection.label or ""),
      matchedRule = type(matchedRule) == "table" and DeepCopy(matchedRule) or nil,
    }
  end

  local function AwardLootToCharacter(name, characterKey, itemName, itemLevel, note, itemID, itemLink)
    local points, matchedRule = ResolveLootPointValue(name, itemName, itemLevel, itemID, itemLink)
    local ok, entry, ledgerRow = AddLootLedgerEntry(name, characterKey, itemName, itemLevel, points, note, itemID, itemLink)
    if not ok then
      return false, entry
    end
    return true, points, entry, ledgerRow, matchedRule
  end

  local function BuildLootSessionParticipationCounts(profile)
    local counts = {}
    if type(profile) ~= "table" or type(profile.sessions) ~= "table" then
      return counts
    end

    for _, session in ipairs(profile.sessions) do
      if type(session) == "table" then
        local countedThisSession = {}
        local members = type(session.members) == "table" and session.members or nil
        if members then
          for memberKey, member in pairs(members) do
            local resolvedKey = TrimText(memberKey ~= "" and memberKey or (type(member) == "table" and member.name or ""))
            local status = TrimText(type(member) == "table" and member.status or "JOINED")
            if resolvedKey ~= "" and status ~= "DECLINED" and not countedThisSession[resolvedKey] then
              counts[resolvedKey] = (tonumber(counts[resolvedKey]) or 0) + 1
              countedThisSession[resolvedKey] = true
            end
          end
        end

        local hostKey = TrimText(session.host)
        if hostKey ~= "" and not countedThisSession[hostKey] then
          counts[hostKey] = (tonumber(counts[hostKey]) or 0) + 1
        end
      end
    end

    return counts
  end

  local function GetLootLedgerCharacters(name)
    local profile = GetLootProfile(name)
    local cacheKey = string.lower(TrimText(name ~= nil and name or "Default"))
    local profileRevision = GetLootProfileRevision(profile)
    local sessionCounts = BuildLootSessionParticipationCounts(profile)
    local metaByCharacter = EnsureLootLedgerMeta(profile)
    local rows = {}
    local added = {}
    for key, entry in pairs(profile.lootLedger or {}) do
      local meta = type(metaByCharacter[key]) == "table" and metaByCharacter[key] or nil
      local awardCounters = CountLootLedgerAwardCounters(type(entry) == "table" and entry.items or nil)
      local totalPoints = type(entry) == "table" and RecalculateLootLedgerRowTotal(entry) or 0
      rows[#rows + 1] = {
        character = key,
        totalPoints = totalPoints,
        itemCount = CountLootLedgerItemEntries(type(entry) == "table" and entry.items or nil),
        sessionCount = tonumber(sessionCounts[key]) or 0,
        bisCount = tonumber(awardCounters.bis) or 0,
        offSpecCount = tonumber(awardCounters.offSpec) or 0,
        transmogCount = tonumber(awardCounters.transmog) or 0,
        disenchantCount = tonumber(awardCounters.disenchant) or 0,
        penaltyPoints = tonumber(meta and meta.penaltyPoints) or 0,
        classFile = meta and meta.classFile or "",
        className = meta and meta.className or "",
        specName = meta and meta.specName or "",
        specIcon = meta and meta.specIcon or "",
        note = meta and meta.note or "",
        mainAltRole = NormalizeLootLedgerMainAltRole(meta and meta.mainAltRole),
        mainCharacter = meta and meta.mainCharacter or "",
      }
      added[key] = true
    end
    for key, sessionCount in pairs(sessionCounts) do
      if not added[key] then
        local meta = type(metaByCharacter[key]) == "table" and metaByCharacter[key] or nil
        rows[#rows + 1] = {
          character = key,
          totalPoints = 0,
          itemCount = 0,
          sessionCount = tonumber(sessionCount) or 0,
          bisCount = 0,
          offSpecCount = 0,
          transmogCount = 0,
          disenchantCount = 0,
          penaltyPoints = tonumber(meta and meta.penaltyPoints) or 0,
          classFile = meta and meta.classFile or "",
          className = meta and meta.className or "",
          specName = meta and meta.specName or "",
          specIcon = meta and meta.specIcon or "",
          note = meta and meta.note or "",
          mainAltRole = NormalizeLootLedgerMainAltRole(meta and meta.mainAltRole),
          mainCharacter = meta and meta.mainCharacter or "",
        }
        added[key] = true
      end
    end
    for key, meta in pairs(metaByCharacter) do
      if not added[key] then
        rows[#rows + 1] = {
          character = key,
          totalPoints = 0,
          itemCount = 0,
          sessionCount = 0,
          bisCount = 0,
          offSpecCount = 0,
          transmogCount = 0,
          disenchantCount = 0,
          penaltyPoints = tonumber(type(meta) == "table" and meta.penaltyPoints) or 0,
          classFile = type(meta) == "table" and meta.classFile or "",
          className = type(meta) == "table" and meta.className or "",
          specName = type(meta) == "table" and meta.specName or "",
          specIcon = type(meta) == "table" and meta.specIcon or "",
          note = type(meta) == "table" and meta.note or "",
          mainAltRole = NormalizeLootLedgerMainAltRole(type(meta) == "table" and meta.mainAltRole),
          mainCharacter = type(meta) == "table" and meta.mainCharacter or "",
        }
      end
    end
    table.sort(rows, function(a, b)
      if (a.totalPoints or 0) == (b.totalPoints or 0) then
        return string.lower(tostring(a.character or "")) < string.lower(tostring(b.character or ""))
      end
      return (a.totalPoints or 0) > (b.totalPoints or 0)
    end)
    lootLedgerCharactersCache[cacheKey] = {
      revision = profileRevision,
      rows = DeepCopy(rows),
    }
    return rows
  end

  return {
    AddLootLedgerEntry = AddLootLedgerEntry,
    RemoveLootLedgerEntry = RemoveLootLedgerEntry,
    ResolveLootPointValue = ResolveLootPointValue,
    ResolveLootAwardOutcome = ResolveLootAwardOutcome,
    AwardLootToCharacter = AwardLootToCharacter,
    GetLootLedgerCharacters = GetLootLedgerCharacters,
  }
end
