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_CreateLootSessionSyncConflictResolverHelpers_Impl = function(deps)
  deps = type(deps) == "table" and deps or {}

  local ApplyFrameSkin = deps.ApplyFrameSkin
  local TrimText = deps.TrimText

  local function trim(value)
    if type(TrimText) == "function" then
      return TrimText(value)
    end
    local text = tostring(value or "")
    text = text:gsub("^%s+", "")
    text = text:gsub("%s+$", "")
    return text
  end

  local function ensureMemberState(editor, memberKey)
    editor.lootSessionConflictSelectionState = type(editor.lootSessionConflictSelectionState) == "table"
      and editor.lootSessionConflictSelectionState
      or {}
    local resolvedMemberKey = trim(memberKey)
    editor.lootSessionConflictSelectionState[resolvedMemberKey] = type(editor.lootSessionConflictSelectionState[resolvedMemberKey]) == "table"
      and editor.lootSessionConflictSelectionState[resolvedMemberKey]
      or {}
    return editor.lootSessionConflictSelectionState[resolvedMemberKey]
  end

  local function buildVisibleRows(detailConflict)
    local visible = {}
    for _, leaf in ipairs(type(detailConflict) == "table" and type(detailConflict.leaves) == "table" and detailConflict.leaves or {}) do
      local leafLabel = trim(type(leaf) == "table" and leaf.label or "")
      for _, row in ipairs(type(leaf) == "table" and type(leaf.rows) == "table" and leaf.rows or {}) do
        visible[#visible + 1] = {
          subdomain = trim(type(leaf) == "table" and leaf.subdomain or ""),
          leafLabel = leafLabel ~= "" and leafLabel or trim(type(leaf) == "table" and leaf.subdomain or ""),
          row = row,
        }
      end
    end
    table.sort(visible, function(left, right)
      local leftLabel = string.lower(tostring(left.leafLabel or ""))
      local rightLabel = string.lower(tostring(right.leafLabel or ""))
      if leftLabel ~= rightLabel then
        return leftLabel < rightLabel
      end
      return string.lower(tostring(type(left.row) == "table" and left.row.pathLabel or "")) < string.lower(tostring(type(right.row) == "table" and right.row.pathLabel or ""))
    end)
    return visible
  end

  local function isRecommended(detailConflict)
    local comparison = string.lower(trim(type(detailConflict) == "table" and detailConflict.comparison or ""))
    return comparison == "remote_newer"
  end

  local function applyPreset(editor, memberKey, detailConflict, mode)
    local state = ensureMemberState(editor, memberKey)
    for _, visible in ipairs(buildVisibleRows(detailConflict)) do
      local rowId = trim(type(visible.row) == "table" and visible.row.id or "")
      if rowId ~= "" then
        if mode == "all" then
          state[rowId] = true
        elseif mode == "recommended" then
          state[rowId] = isRecommended(detailConflict)
        else
          state[rowId] = false
        end
      end
    end
  end

  local function ensureRows(frame, count)
    frame.rows = frame.rows or {}
    while #frame.rows < count do
      local row = CreateFrame("Frame", nil, frame.scrollChild)
      row:SetHeight(42)

      local check = CreateFrame("CheckButton", nil, row, "UICheckButtonTemplate")
      check:SetSize(22, 22)
      row.check = check

      local scopeText = row:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
      scopeText:SetJustifyH("LEFT")
      scopeText:SetTextColor(0.95, 0.85, 0.42, 1.00)
      row.scopeText = scopeText

      local pathText = row:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
      pathText:SetJustifyH("LEFT")
      pathText:SetTextColor(0.86, 0.88, 0.94, 1.00)
      row.pathText = pathText

      local hostText = row:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
      hostText:SetJustifyH("LEFT")
      hostText:SetTextColor(0.38, 0.78, 1.00, 1.00)
      row.hostText = hostText

      local memberText = row:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
      memberText:SetJustifyH("LEFT")
      memberText:SetTextColor(1.00, 0.82, 0.36, 1.00)
      row.memberText = memberText

      frame.rows[#frame.rows + 1] = row
    end
  end

  local function EnsureConflictResolverFrame(editor, parent)
    if not editor or not parent then
      return nil
    end
    if editor.lootSessionSyncConflictResolver then
      return editor.lootSessionSyncConflictResolver
    end

    local frame = CreateFrame("Frame", nil, parent, "BackdropTemplate")
    ApplyFrameSkin(frame)
    if frame.SetBackdropColor then
      frame:SetBackdropColor(0.05, 0.05, 0.07, 0.96)
    end
    frame:Hide()

    local title = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    title:SetPoint("TOPLEFT", 10, -10)
    title:SetText("Nested Preview Resolver")
    frame.title = title

    local hint = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    hint:SetJustifyH("LEFT")
    hint:SetPoint("TOPLEFT", 10, -28)
    hint:SetPoint("TOPRIGHT", -10, -28)
    hint:SetText("")
    frame.hint = hint

    local recommendedBtn = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
    recommendedBtn:SetSize(110, 22)
    recommendedBtn:SetText("Recommended")
    frame.recommendedBtn = recommendedBtn

    local allBtn = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
    allBtn:SetSize(110, 22)
    allBtn:SetText("Take Member All")
    frame.allBtn = allBtn

    local clearBtn = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
    clearBtn:SetSize(70, 22)
    clearBtn:SetText("Clear")
    frame.clearBtn = clearBtn

    local summaryText = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    summaryText:SetJustifyH("LEFT")
    summaryText:SetText("")
    frame.summaryText = summaryText

    local header = CreateFrame("Frame", nil, frame)
    frame.header = header

    local headerScope = header:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    headerScope:SetJustifyH("LEFT")
    headerScope:SetText("Leaf")
    frame.headerScope = headerScope

    local headerPath = header:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    headerPath:SetJustifyH("LEFT")
    headerPath:SetText("Path")
    frame.headerPath = headerPath

    local headerHost = header:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    headerHost:SetJustifyH("LEFT")
    headerHost:SetText("Host")
    frame.headerHost = headerHost

    local headerMember = header:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    headerMember:SetJustifyH("LEFT")
    headerMember:SetText("Member")
    frame.headerMember = headerMember

    local scrollFrame = CreateFrame("ScrollFrame", nil, frame, "UIPanelScrollFrameTemplate")
    frame.scrollFrame = scrollFrame

    local scrollChild = CreateFrame("Frame", nil, scrollFrame)
    scrollChild:SetSize(1, 1)
    scrollFrame:SetScrollChild(scrollChild)
    frame.scrollChild = scrollChild

    editor.lootSessionSyncConflictResolver = frame
    return frame
  end

  local function BuildSelectedConflictResolution(editor, candidate, detailConflict)
    candidate = type(candidate) == "table" and candidate or {}
    local memberKey = trim(candidate.memberKey)
    local state = ensureMemberState(editor, memberKey)
    local selectionsBySubdomain = {}
    local selectedCount = 0
    for _, visible in ipairs(buildVisibleRows(detailConflict)) do
      local row = type(visible.row) == "table" and visible.row or {}
      local rowId = trim(row.id)
      if rowId ~= "" and state[rowId] == true then
        selectionsBySubdomain[visible.subdomain] = selectionsBySubdomain[visible.subdomain] or {}
        selectionsBySubdomain[visible.subdomain][#selectionsBySubdomain[visible.subdomain] + 1] = rowId
        selectedCount = selectedCount + 1
      end
    end
    return {
      selectionsBySubdomain = selectionsBySubdomain,
      selectedCount = selectedCount,
      selectionActive = selectedCount > 0,
      targetMemberKey = memberKey,
    }
  end

  local function RefreshSyncConflictResolver(editor, parent, candidate, detailConflict)
    local frame = EnsureConflictResolverFrame(editor, parent)
    if not frame then
      return nil
    end

    candidate = type(candidate) == "table" and candidate or {}
    detailConflict = type(detailConflict) == "table" and detailConflict or nil
    if type(detailConflict) ~= "table"
      or trim(detailConflict.memberKey) == ""
      or trim(detailConflict.memberKey) ~= trim(candidate.memberKey)
      or type(detailConflict.leaves) ~= "table"
      or #detailConflict.leaves == 0 then
      frame:Hide()
      return frame
    end

    local memberKey = trim(candidate.memberKey)
    local state = ensureMemberState(editor, memberKey)
    local visibleRows = buildVisibleRows(detailConflict)
    ensureRows(frame, #visibleRows)

    if frame.hint then
      frame.hint:SetText("Checked rows take the member value for only that nested preview path. Unchecked rows keep the current host copy. Applying also queues direct host repair for the affected leaf scopes.")
    end

    if frame.recommendedBtn then
      frame.recommendedBtn:SetScript("OnClick", function()
        applyPreset(editor, memberKey, detailConflict, "recommended")
        RefreshSyncConflictResolver(editor, parent, candidate, detailConflict)
      end)
    end
    if frame.allBtn then
      frame.allBtn:SetScript("OnClick", function()
        applyPreset(editor, memberKey, detailConflict, "all")
        RefreshSyncConflictResolver(editor, parent, candidate, detailConflict)
      end)
    end
    if frame.clearBtn then
      frame.clearBtn:SetScript("OnClick", function()
        applyPreset(editor, memberKey, detailConflict, "clear")
        RefreshSyncConflictResolver(editor, parent, candidate, detailConflict)
      end)
    end

    local selectedCount = 0
    for index, visible in ipairs(visibleRows) do
      local row = frame.rows[index]
      local detailRow = type(visible.row) == "table" and visible.row or {}
      local rowId = trim(detailRow.id)
      if state[rowId] == nil and isRecommended(detailConflict) then
        state[rowId] = true
      end
      if state[rowId] == true then
        selectedCount = selectedCount + 1
      end

      row:Show()
      row:ClearAllPoints()
      row:SetPoint("TOPLEFT", 0, -((index - 1) * 44))
      row:SetPoint("TOPRIGHT", -18, -((index - 1) * 44))

      row.check:ClearAllPoints()
      row.check:SetPoint("TOPLEFT", 0, -8)
      row.check:SetChecked(state[rowId] == true)
      row.check:SetScript("OnClick", function(self)
        state[rowId] = self:GetChecked() and true or false
        RefreshSyncConflictResolver(editor, parent, candidate, detailConflict)
      end)

      row.scopeText:ClearAllPoints()
      row.scopeText:SetPoint("TOPLEFT", 26, -2)
      row.scopeText:SetWidth(130)
      row.scopeText:SetText(tostring(visible.leafLabel or "-"))

      row.pathText:ClearAllPoints()
      row.pathText:SetPoint("TOPLEFT", 160, -2)
      row.pathText:SetWidth(240)
      row.pathText:SetText(tostring(detailRow.pathLabel or "-"))

      row.hostText:ClearAllPoints()
      row.hostText:SetPoint("TOPLEFT", 405, -2)
      row.hostText:SetWidth(150)
      row.hostText:SetText(tostring(detailRow.hostSummary or "-"))

      row.memberText:ClearAllPoints()
      row.memberText:SetPoint("TOPLEFT", 560, -2)
      row.memberText:SetWidth(150)
      row.memberText:SetText(tostring(detailRow.memberSummary or "-"))
    end

    for index = #visibleRows + 1, #frame.rows do
      frame.rows[index]:Hide()
    end

    frame.scrollChild:SetHeight(math.max(1, #visibleRows * 44))
    frame.scrollChild:SetWidth(700)
    frame:SetHeight(250)
    frame:ClearAllPoints()
    frame:SetPoint("BOTTOMLEFT", parent, "BOTTOMLEFT", 14, 48)
    frame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMRIGHT", -14, 48)

    frame.recommendedBtn:ClearAllPoints()
    frame.recommendedBtn:SetPoint("TOPLEFT", 10, -48)
    frame.allBtn:ClearAllPoints()
    frame.allBtn:SetPoint("LEFT", frame.recommendedBtn, "RIGHT", 6, 0)
    frame.clearBtn:ClearAllPoints()
    frame.clearBtn:SetPoint("LEFT", frame.allBtn, "RIGHT", 6, 0)

    frame.summaryText:ClearAllPoints()
    frame.summaryText:SetPoint("LEFT", frame.clearBtn, "RIGHT", 10, 0)
    frame.summaryText:SetText(tostring(selectedCount) .. " / " .. tostring(#visibleRows) .. " preview rows selected for member apply and direct leaf repair sync.")

    frame.header:ClearAllPoints()
    frame.header:SetPoint("TOPLEFT", 10, -78)
    frame.header:SetPoint("TOPRIGHT", -26, -78)
    frame.header:SetHeight(18)
    frame.headerScope:ClearAllPoints()
    frame.headerScope:SetPoint("TOPLEFT", 26, 0)
    frame.headerPath:ClearAllPoints()
    frame.headerPath:SetPoint("TOPLEFT", 160, 0)
    frame.headerHost:ClearAllPoints()
    frame.headerHost:SetPoint("TOPLEFT", 405, 0)
    frame.headerMember:ClearAllPoints()
    frame.headerMember:SetPoint("TOPLEFT", 560, 0)

    frame.scrollFrame:ClearAllPoints()
    frame.scrollFrame:SetPoint("TOPLEFT", 10, -98)
    frame.scrollFrame:SetPoint("BOTTOMRIGHT", -28, 10)

    frame:Show()
    return frame
  end

  return {
    EnsureConflictResolverFrame = EnsureConflictResolverFrame,
    RefreshSyncConflictResolver = RefreshSyncConflictResolver,
    BuildSelectedConflictResolution = BuildSelectedConflictResolution,
  }
end
