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

  local ApplyFrameSkin = deps.ApplyFrameSkin
  local ResolveOptionalFunction = deps.ResolveOptionalFunction
  local BindPopupBoardDragScripts = deps.BindPopupBoardDragScripts
  local ApplyPopupBoardResizeLimits = deps.ApplyPopupBoardResizeLimits
  local RaisePopupFrameAboveEditor = deps.RaisePopupFrameAboveEditor
  local ApplyBoardButtonStyle = deps.ApplyBoardButtonStyle
  local ApplyBoardSectionSkin = deps.ApplyBoardSectionSkin
  local StartPopupBoardResize = deps.StartPopupBoardResize
  local StopPopupBoardResize = deps.StopPopupBoardResize
  local ShowBoardItemTooltip = deps.ShowBoardItemTooltip
  local HideBoardItemTooltip = deps.HideBoardItemTooltip
  local TrimText = deps.TrimText
  local DEFAULT_POPUP_BOARD_WIDTH = tonumber(deps.DEFAULT_POPUP_BOARD_WIDTH) or 760
  local DEFAULT_POPUP_BOARD_HEIGHT = tonumber(deps.DEFAULT_POPUP_BOARD_HEIGHT) or 560
  local OPTIONAL_MEMBER_COLUMNS = {
    { key = "total", label = "Points", tooltip = "Total points" },
    { key = "bis", label = "BiS", tooltip = "Best in Slot items" },
    { key = "dice", label = "Dice", tooltip = "Dice roll (1-100)" },
    { key = "offspec", label = "OS", tooltip = "Off-Spec items" },
    { key = "transmog", label = "TM", tooltip = "Transmog items" },
    { key = "disenchant", label = "DE", tooltip = "Disenchant items" },
    { key = "items", label = "Items", tooltip = "Received items" },
  }

  local function CreateBoardFrameScaffold(callbacks)
    callbacks = type(callbacks) == "table" and callbacks or {}
    local BuildBoardHeaderButton = callbacks.BuildBoardHeaderButton

    local frame = CreateFrame("Frame", "LIDCOUNCIL_LiveLootBoard", UIParent, "BackdropTemplate")
    frame:SetSize(DEFAULT_POPUP_BOARD_WIDTH, DEFAULT_POPUP_BOARD_HEIGHT)
    frame:SetPoint("CENTER", 0, 40)
    frame:SetFrameStrata("FULLSCREEN_DIALOG")
    frame:SetMovable(true)
    frame:SetResizable(true)
    frame:SetToplevel(true)
    frame:EnableMouse(true)
    if type(BindPopupBoardDragScripts) == "function" then
      BindPopupBoardDragScripts(frame)
    end
    if type(ApplyPopupBoardResizeLimits) == "function" then
      ApplyPopupBoardResizeLimits(frame)
    end
    if type(ApplyFrameSkin) == "function" then
      ApplyFrameSkin(frame)
    end
    frame:HookScript("OnShow", function(self)
      if not self.__embeddedParent and type(RaisePopupFrameAboveEditor) == "function" then
        RaisePopupFrameAboveEditor(self, "FULLSCREEN_DIALOG")
      end
    end)
    frame:Hide()

    local title = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    title:SetPoint("TOPLEFT", 16, -14)
    title:SetJustifyH("LEFT")
    title:SetText("LidCouncil Live Board")
    frame.title = title
    local titleWidth = math.max(160, math.ceil((title.GetStringWidth and title:GetStringWidth()) or 180))

    local note = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    note:SetPoint("TOPLEFT", 16, -38)
    note:SetWidth(724)
    note:SetJustifyH("LEFT")
    note:SetText("Live loot selection board for the session host.")
    frame.note = note

    local hostToolsLabel = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    hostToolsLabel:SetText("HOST TOOLS")
    hostToolsLabel:SetTextColor(0.55, 0.62, 0.72, 1)
    hostToolsLabel:SetJustifyH("RIGHT")
    hostToolsLabel:Hide()
    frame.hostToolsLabel = hostToolsLabel

    local closeBtn = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
    closeBtn:SetSize(84, 22)
    closeBtn:SetPoint("TOPRIGHT", -16, -12)
    closeBtn:SetText("Hide Board")
    closeBtn.__lidBoardWindowControl = true
    if type(ApplyBoardButtonStyle) == "function" then
      ApplyBoardButtonStyle(closeBtn)
    end
    if type(callbacks.OnClose) == "function" then
      closeBtn:SetScript("OnClick", function()
        callbacks.OnClose(frame)
      end)
    end
    frame.closeBtn = closeBtn

    local collapseBtn = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
    collapseBtn:SetSize(66, 20)
    collapseBtn:SetPoint("TOPLEFT", 16 + titleWidth + 12, -12)
    collapseBtn:SetText("Collapse")
    collapseBtn.__lidBoardWindowControl = true
    if type(ApplyBoardButtonStyle) == "function" then
      ApplyBoardButtonStyle(collapseBtn)
    end
    if type(callbacks.OnCollapse) == "function" then
      collapseBtn:SetScript("OnClick", function()
        callbacks.OnCollapse(frame)
      end)
    end
    frame.collapseBtn = collapseBtn

    local boardSyncBtn = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
    boardSyncBtn:SetSize(88, 22)
    boardSyncBtn:SetPoint("LEFT", collapseBtn, "RIGHT", 8, 0)
    boardSyncBtn:SetText("Sync Board")
    boardSyncBtn.__lidBoardUtility = true
    if type(ApplyBoardButtonStyle) == "function" then
      ApplyBoardButtonStyle(boardSyncBtn)
    end
    boardSyncBtn:SetScript("OnEnter", function(self)
      if type(GameTooltip) ~= "table" then
        return
      end
      GameTooltip:SetOwner(self, "ANCHOR_BOTTOM")
      GameTooltip:SetText("Sync Board", 0.60, 0.76, 0.90, 1.00)
      GameTooltip:AddLine("Host only: send the current Live Board state to all joined session members.", 0.92, 0.92, 0.96, true)
      GameTooltip:AddLine("Unavailable during combat.", 0.72, 0.72, 0.76, true)
      GameTooltip:Show()
    end)
    boardSyncBtn:SetScript("OnLeave", function()
      if type(GameTooltip) == "table" then
        GameTooltip:Hide()
      end
    end)
    if type(callbacks.OnSendBoardSync) == "function" then
      boardSyncBtn:SetScript("OnClick", function()
        callbacks.OnSendBoardSync(frame)
      end)
    end
    frame.boardSyncBtn = boardSyncBtn

    local tradeHelperBtn = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
    tradeHelperBtn:SetSize(104, 22)
    tradeHelperBtn:SetPoint("LEFT", boardSyncBtn, "RIGHT", 8, 0)
    tradeHelperBtn:SetText("Trade Helper")
    tradeHelperBtn.__lidBoardUtility = true
    if type(ApplyBoardButtonStyle) == "function" then
      ApplyBoardButtonStyle(tradeHelperBtn)
    end
    tradeHelperBtn:SetScript("OnEnter", function(self)
      if type(GameTooltip) ~= "table" then
        return
      end
      GameTooltip:SetOwner(self, "ANCHOR_BOTTOM")
      GameTooltip:SetText("Trade Helper", 0.60, 0.76, 0.90, 1.00)
      GameTooltip:AddLine("Host only: review assigned Live Board items and record their manual trade confirmation.", 0.92, 0.92, 0.96, true)
      GameTooltip:Show()
    end)
    tradeHelperBtn:SetScript("OnLeave", function()
      if type(GameTooltip) == "table" then
        GameTooltip:Hide()
      end
    end)
    if type(callbacks.OnTradeHelper) == "function" then
      tradeHelperBtn:SetScript("OnClick", function()
        callbacks.OnTradeHelper(frame)
      end)
    end
    frame.tradeHelperBtn = tradeHelperBtn

    local tradeHelperBadge = CreateFrame("Button", nil, tradeHelperBtn)
    tradeHelperBadge:SetSize(16, 16)
    tradeHelperBadge:SetPoint("TOPRIGHT", tradeHelperBtn, "TOPRIGHT", 4, 4)
    if tradeHelperBadge.SetFrameLevel and tradeHelperBtn.GetFrameLevel then
      tradeHelperBadge:SetFrameLevel((tradeHelperBtn:GetFrameLevel() or 1) + 2)
    end
    local tradeHelperBadgeBg = tradeHelperBadge:CreateTexture(nil, "BACKGROUND")
    tradeHelperBadgeBg:SetAllPoints(tradeHelperBadge)
    tradeHelperBadgeBg:SetTexture("Interface\\Buttons\\WHITE8x8")
    tradeHelperBadgeBg:SetVertexColor(0.12, 0.27, 0.42, 0.98)
    local tradeHelperBadgeText = tradeHelperBadge:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    tradeHelperBadgeText:SetAllPoints(tradeHelperBadge)
    tradeHelperBadgeText:SetJustifyH("CENTER")
    tradeHelperBadgeText:SetJustifyV("MIDDLE")
    tradeHelperBadgeText:SetTextColor(0.78, 0.92, 1.00, 1)
    tradeHelperBadgeText:SetText("")
    tradeHelperBadge.text = tradeHelperBadgeText
    tradeHelperBadge:SetScript("OnEnter", function(self)
      if type(GameTooltip) ~= "table" then
        return
      end
      local pendingCount = tonumber(self.text and self.text.GetText and self.text:GetText()) or 0
      GameTooltip:SetOwner(self, "ANCHOR_BOTTOM")
      GameTooltip:SetText("Pending Trades", 0.60, 0.76, 0.90, 1.00)
      GameTooltip:AddLine(tostring(pendingCount) .. " assigned item" .. (pendingCount == 1 and "" or "s") .. " still need manual trade confirmation.", 0.92, 0.92, 0.96, true)
      GameTooltip:AddLine("Open Trade Helper to review them.", 0.72, 0.72, 0.76, true)
      GameTooltip:Show()
    end)
    tradeHelperBadge:SetScript("OnLeave", function()
      if type(GameTooltip) == "table" then
        GameTooltip:Hide()
      end
    end)
    tradeHelperBadge:SetScript("OnClick", function()
      if tradeHelperBtn.IsEnabled and tradeHelperBtn:IsEnabled() then
        tradeHelperBtn:Click()
      end
    end)
    tradeHelperBadge:Hide()
    frame.tradeHelperBadge = tradeHelperBadge

    local itemsPanel = CreateFrame("Frame", nil, frame, "BackdropTemplate")
    if type(ApplyBoardSectionSkin) == "function" then
      ApplyBoardSectionSkin(itemsPanel)
    end
    frame.itemsPanel = itemsPanel

    local selectionPanel = CreateFrame("Frame", nil, frame, "BackdropTemplate")
    if type(ApplyBoardSectionSkin) == "function" then
      ApplyBoardSectionSkin(selectionPanel)
    end
    frame.selectionPanel = selectionPanel

    local assignmentPanel = CreateFrame("Frame", nil, frame, "BackdropTemplate")
    if type(ApplyBoardSectionSkin) == "function" then
      ApplyBoardSectionSkin(assignmentPanel)
    end
    frame.assignmentPanel = assignmentPanel

    local assignmentReadinessTint = assignmentPanel:CreateTexture(nil, "BACKGROUND")
    assignmentReadinessTint:SetAllPoints(assignmentPanel)
    assignmentReadinessTint:SetTexture("Interface\\Buttons\\WHITE8x8")
    assignmentReadinessTint:SetVertexColor(0, 0, 0, 0)
    frame.assignmentReadinessTint = assignmentReadinessTint

    local assignmentReadinessBorder = {}
    local function CreateAssignmentReadinessEdge()
      local edge = assignmentPanel:CreateTexture(nil, "BORDER")
      edge:SetTexture("Interface\\Buttons\\WHITE8x8")
      edge:SetVertexColor(0.55, 0.55, 0.60, 0.72)
      assignmentReadinessBorder[#assignmentReadinessBorder + 1] = edge
      return edge
    end
    local readinessTop = CreateAssignmentReadinessEdge()
    readinessTop:SetPoint("TOPLEFT", assignmentPanel, "TOPLEFT", 0, 0)
    readinessTop:SetPoint("TOPRIGHT", assignmentPanel, "TOPRIGHT", 0, 0)
    readinessTop:SetHeight(1)
    local readinessBottom = CreateAssignmentReadinessEdge()
    readinessBottom:SetPoint("BOTTOMLEFT", assignmentPanel, "BOTTOMLEFT", 0, 0)
    readinessBottom:SetPoint("BOTTOMRIGHT", assignmentPanel, "BOTTOMRIGHT", 0, 0)
    readinessBottom:SetHeight(1)
    local readinessLeft = CreateAssignmentReadinessEdge()
    readinessLeft:SetPoint("TOPLEFT", assignmentPanel, "TOPLEFT", 0, 0)
    readinessLeft:SetPoint("BOTTOMLEFT", assignmentPanel, "BOTTOMLEFT", 0, 0)
    readinessLeft:SetWidth(1)
    local readinessRight = CreateAssignmentReadinessEdge()
    readinessRight:SetPoint("TOPRIGHT", assignmentPanel, "TOPRIGHT", 0, 0)
    readinessRight:SetPoint("BOTTOMRIGHT", assignmentPanel, "BOTTOMRIGHT", 0, 0)
    readinessRight:SetWidth(1)
    frame.assignmentReadinessBorder = assignmentReadinessBorder

    local membersPanel = CreateFrame("Frame", nil, frame, "BackdropTemplate")
    if type(ApplyBoardSectionSkin) == "function" then
      ApplyBoardSectionSkin(membersPanel)
    end
    frame.membersPanel = membersPanel

    local leftHeader = itemsPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    leftHeader:SetPoint("TOPLEFT", 18, -72)
    leftHeader:SetText("Dropped Items (0)")
    frame.leftHeader = leftHeader

    local assignedHeader = itemsPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    assignedHeader:SetPoint("TOPLEFT", 18, -120)
    assignedHeader:SetText("Assigned Items (0)")
    assignedHeader:Hide()
    frame.assignedHeader = assignedHeader

    local tradedHeader = itemsPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    tradedHeader:SetPoint("TOPLEFT", 18, -148)
    tradedHeader:SetText("Traded Items (0)")
    tradedHeader:Hide()
    frame.tradedHeader = tradedHeader

    local rightHeader = selectionPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    rightHeader:SetPoint("TOPLEFT", 268, -72)
    rightHeader:SetText("Selected Item")
    frame.rightHeader = rightHeader

    local memberSectionTitle = membersPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    memberSectionTitle:SetPoint("TOPLEFT", 268, -292)
    memberSectionTitle:SetText("Candidates & Council Votes")
    frame.memberSectionTitle = memberSectionTitle

    local memberColumnToggleLabel = membersPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    memberColumnToggleLabel:SetPoint("TOPLEFT", 268, -316)
    memberColumnToggleLabel:SetText("Columns:")
    frame.memberColumnToggleLabel = memberColumnToggleLabel

    local memberColumnToggleFrame = CreateFrame("Frame", nil, membersPanel)
    memberColumnToggleFrame:SetSize(410, 22)
    memberColumnToggleFrame:SetPoint("TOPLEFT", 324, -314)
    frame.memberColumnToggleFrame = memberColumnToggleFrame
    frame.memberColumnToggles = {}
    for index, column in ipairs(OPTIONAL_MEMBER_COLUMNS) do
      local check = CreateFrame("CheckButton", nil, memberColumnToggleFrame, "UICheckButtonTemplate")
      check:SetSize(20, 20)
      check.__columnKey = column.key
      check.__columnLabel = column.label
      check.__tooltipText = column.tooltip
      local text = check:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
      text:SetPoint("LEFT", check, "RIGHT", -1, 0)
      text:SetText(column.label)
      check.text = text
      check:SetScript("OnClick", function(self)
        if type(callbacks.OnToggleMemberColumn) == "function" then
          callbacks.OnToggleMemberColumn(frame, self.__columnKey, self:GetChecked() and true or false)
        end
      end)
      check:SetScript("OnEnter", function(self)
        if type(GameTooltip) == "table" and TrimText(self.__tooltipText) ~= "" then
          GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
          GameTooltip:SetText(tostring(self.__tooltipText), 1.00, 0.92, 0.35, 1.00, true)
          GameTooltip:Show()
        end
      end)
      check:SetScript("OnLeave", function()
        if type(GameTooltip) == "table" then
          GameTooltip:Hide()
        end
      end)
      frame.memberColumnToggles[index] = check
    end

    frame.itemButtons = {}
    for i = 1, 14 do
      local button = CreateFrame("Button", nil, itemsPanel)
      button:SetSize(220, 22)
      button:SetPoint("TOPLEFT", 16, -76 - (i * 24))
      button:EnableMouse(true)
      local bg = button:CreateTexture(nil, "BACKGROUND")
      bg:SetAllPoints(true)
      bg:SetTexture("Interface\\Buttons\\WHITE8x8")
      bg:SetVertexColor(0.09, 0.08, 0.10, 0.92)
      button.__bg = bg
      local highlight = button:CreateTexture(nil, "ARTWORK")
      highlight:SetAllPoints(true)
      highlight:SetTexture("Interface\\Buttons\\WHITE8x8")
      highlight:SetVertexColor(0.90, 0.74, 0.18, 0.12)
      highlight:Hide()
      button.__highlight = highlight
      local itemIcon = button:CreateTexture(nil, "ARTWORK")
      itemIcon:SetSize(16, 16)
      itemIcon:SetPoint("LEFT", 6, 0)
      button.itemIcon = itemIcon
      local localVoteMarker = button:CreateTexture(nil, "ARTWORK")
      localVoteMarker:SetSize(12, 12)
      localVoteMarker:SetPoint("LEFT", 28, 0)
      localVoteMarker:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
      localVoteMarker:Hide()
      button.localVoteMarker = localVoteMarker
      local itemText = button:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
      itemText:SetPoint("LEFT", button, "LEFT", 28, 0)
      itemText:SetPoint("RIGHT", button, "RIGHT", -6, 0)
      itemText:SetJustifyH("LEFT")
      button.itemText = itemText
      local recipientText = button:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
      recipientText:SetPoint("RIGHT", button, "RIGHT", -6, 0)
      recipientText:SetWidth(82)
      recipientText:SetJustifyH("RIGHT")
      recipientText:SetTextColor(0.38, 0.88, 0.70, 1.00)
      if recipientText.SetWordWrap then recipientText:SetWordWrap(false) end
      if recipientText.SetNonSpaceWrap then recipientText:SetNonSpaceWrap(false) end
      if recipientText.SetMaxLines then recipientText:SetMaxLines(1) end
      recipientText:Hide()
      button.recipientText = recipientText
      if type(callbacks.OnItemEnter) == "function" then
        button:SetScript("OnEnter", function(self)
          callbacks.OnItemEnter(frame, self)
        end)
      end
      if type(callbacks.OnItemLeave) == "function" then
        button:SetScript("OnLeave", function(self)
          callbacks.OnItemLeave(frame, self)
        end)
      end
      if type(callbacks.OnItemClick) == "function" then
        button:SetScript("OnClick", function(self)
          callbacks.OnItemClick(frame, self)
        end)
      end
      button:Hide()
      frame.itemButtons[i] = button
    end

    local resizeHandle = CreateFrame("Button", nil, frame)
    resizeHandle:SetSize(16, 16)
    resizeHandle:SetPoint("BOTTOMRIGHT", -6, 6)
    resizeHandle:SetNormalTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Up")
    resizeHandle:SetHighlightTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Highlight")
    resizeHandle:SetPushedTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Down")
    resizeHandle:RegisterForDrag("LeftButton")
    if type(callbacks.OnResizeStart) == "function" then
      resizeHandle:SetScript("OnDragStart", function(self)
        callbacks.OnResizeStart(frame, self)
      end)
    elseif type(StartPopupBoardResize) == "function" then
      resizeHandle:SetScript("OnDragStart", function(self)
        StartPopupBoardResize(frame, self)
      end)
    end
    if type(callbacks.OnResizeStop) == "function" then
      resizeHandle:SetScript("OnDragStop", function(self)
        callbacks.OnResizeStop(frame, self)
      end)
      resizeHandle:SetScript("OnMouseUp", function(self)
        callbacks.OnResizeStop(frame, self)
      end)
    elseif type(StopPopupBoardResize) == "function" then
      resizeHandle:SetScript("OnDragStop", function(self)
        StopPopupBoardResize(frame, self)
      end)
      resizeHandle:SetScript("OnMouseUp", function(self)
        StopPopupBoardResize(frame, self)
      end)
    end
    frame.resizeHandle = resizeHandle

    local detailIcon = selectionPanel:CreateTexture(nil, "ARTWORK")
    detailIcon:SetSize(32, 32)
    detailIcon:SetPoint("TOPLEFT", 268, -92)
    frame.detailIcon = detailIcon

    local detailTooltipButton = CreateFrame("Button", nil, selectionPanel)
    detailTooltipButton:SetPoint("TOPLEFT", detailIcon, "TOPLEFT", 0, 0)
    detailTooltipButton:SetSize(32, 32)
    detailTooltipButton:EnableMouse(false)
    detailTooltipButton:SetScript("OnEnter", function(self)
      if type(ShowBoardItemTooltip) == "function" then
        ShowBoardItemTooltip(self)
      end
    end)
    detailTooltipButton:SetScript("OnLeave", function()
      if type(HideBoardItemTooltip) == "function" then
        HideBoardItemTooltip()
      end
    end)
    frame.detailTooltipButton = detailTooltipButton

    local detailTitle = selectionPanel:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    detailTitle:SetPoint("TOPLEFT", detailIcon, "TOPRIGHT", 10, -2)
    detailTitle:SetWidth(430)
    detailTitle:SetJustifyH("LEFT")
    frame.detailTitle = detailTitle

    local detailMeta = selectionPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    detailMeta:SetPoint("TOPLEFT", detailIcon, "BOTTOMLEFT", 0, -10)
    detailMeta:SetWidth(470)
    detailMeta:SetJustifyH("LEFT")
    frame.detailMeta = detailMeta

    local assignHeader = assignmentPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    assignHeader:SetPoint("TOPLEFT", 268, -158)
    assignHeader:SetText("Final Assignment")
    frame.assignHeader = assignHeader

    local assignTarget = assignmentPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    assignTarget:SetPoint("TOPLEFT", 268, -182)
    assignTarget:SetWidth(466)
    assignTarget:SetJustifyH("LEFT")
    if assignTarget.SetWordWrap then
      assignTarget:SetWordWrap(false)
    end
    assignTarget:SetText("")
    frame.assignTarget = assignTarget

    local createCustomDropdown = type(ResolveOptionalFunction) == "function" and ResolveOptionalFunction("LIDCOUNCIL_CreateCustomDropdownControl") or nil
    if type(createCustomDropdown) == "function" then
      local assignDropdown = createCustomDropdown(rawget(_G, "LIDCOUNCIL_Editor"), assignmentPanel, {
        width = 280,
        text = "Select session member",
      })
      assignDropdown:SetPoint("TOPLEFT", 268, -218)
      frame.assignDropdown = assignDropdown
    end

    local prevAssignBtn = CreateFrame("Button", nil, assignmentPanel, "UIPanelButtonTemplate")
    prevAssignBtn:SetSize(70, 22)
    prevAssignBtn:SetPoint("TOPLEFT", 268, -208)
    prevAssignBtn:SetText("Prev")
    if type(ApplyBoardButtonStyle) == "function" then
      ApplyBoardButtonStyle(prevAssignBtn)
    end
    prevAssignBtn:Hide()
    if type(callbacks.OnPrevAssign) == "function" then
      prevAssignBtn:SetScript("OnClick", function()
        callbacks.OnPrevAssign(frame)
      end)
    end
    frame.prevAssignBtn = prevAssignBtn

    local nextAssignBtn = CreateFrame("Button", nil, assignmentPanel, "UIPanelButtonTemplate")
    nextAssignBtn:SetSize(70, 22)
    nextAssignBtn:SetPoint("LEFT", prevAssignBtn, "RIGHT", 8, 0)
    nextAssignBtn:SetText("Next")
    if type(ApplyBoardButtonStyle) == "function" then
      ApplyBoardButtonStyle(nextAssignBtn)
    end
    nextAssignBtn:Hide()
    if type(callbacks.OnNextAssign) == "function" then
      nextAssignBtn:SetScript("OnClick", function()
        callbacks.OnNextAssign(frame)
      end)
    end
    frame.nextAssignBtn = nextAssignBtn

    local assignBtn = CreateFrame("Button", nil, assignmentPanel, "UIPanelButtonTemplate")
    assignBtn:SetSize(150, 22)
    if frame.assignDropdown then
      assignBtn:SetPoint("LEFT", frame.assignDropdown, "RIGHT", 12, 0)
    else
      assignBtn:SetPoint("TOPLEFT", 268, -218)
    end
    assignBtn:SetText("Assign Item")
    assignBtn.__lidBoardPrimary = true
    if type(ApplyBoardButtonStyle) == "function" then
      ApplyBoardButtonStyle(assignBtn)
    end
    if type(callbacks.OnAssign) == "function" then
      assignBtn:SetScript("OnClick", function()
        callbacks.OnAssign(frame)
      end)
    end
    frame.assignBtn = assignBtn

    local voteBtn = CreateFrame("Button", nil, assignmentPanel, "UIPanelButtonTemplate")
    voteBtn:SetSize(70, 22)
    voteBtn:SetPoint("TOPLEFT", 268, -238)
    voteBtn:SetText("Vote")
    if type(ApplyBoardButtonStyle) == "function" then
      ApplyBoardButtonStyle(voteBtn)
    end
    voteBtn:Hide()
    if type(callbacks.OnVote) == "function" then
      voteBtn:SetScript("OnClick", function()
        callbacks.OnVote(frame)
      end)
    end
    frame.voteBtn = voteBtn

    local unassignBtn = CreateFrame("Button", nil, assignmentPanel, "UIPanelButtonTemplate")
    unassignBtn:SetSize(86, 22)
    unassignBtn:SetPoint("TOPLEFT", 268, -104)
    unassignBtn:SetText("Unassign")
    if type(ApplyBoardButtonStyle) == "function" then
      ApplyBoardButtonStyle(unassignBtn)
    end
    if type(callbacks.OnUnassign) == "function" then
      unassignBtn:SetScript("OnClick", function()
        callbacks.OnUnassign(frame)
      end)
    end
    frame.unassignBtn = unassignBtn

    local changeRollBtn = CreateFrame("Button", nil, assignmentPanel, "UIPanelButtonTemplate")
    changeRollBtn:SetSize(112, 22)
    changeRollBtn:SetPoint("LEFT", unassignBtn, "RIGHT", 10, 0)
    changeRollBtn:SetText("Override Roll")
    if type(ApplyBoardButtonStyle) == "function" then
      ApplyBoardButtonStyle(changeRollBtn)
    end
    changeRollBtn:SetScript("OnEnter", function(self)
      if type(GameTooltip) == "table" then
        GameTooltip:SetOwner(self, "ANCHOR_TOP")
        GameTooltip:SetText("Override Roll Choice", 1.00, 0.82, 0.28, 1.00)
        GameTooltip:AddLine("Host only: change the selected candidate's recorded roll response.", 0.92, 0.92, 0.96, true)
        GameTooltip:Show()
      end
    end)
    changeRollBtn:SetScript("OnLeave", function()
      if type(GameTooltip) == "table" then
        GameTooltip:Hide()
      end
    end)
    if type(callbacks.OnChangeRoll) == "function" then
      changeRollBtn:SetScript("OnClick", function()
        callbacks.OnChangeRoll(frame)
      end)
    end
    frame.changeRollBtn = changeRollBtn

    local assignmentReadiness = assignmentPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    assignmentReadiness:SetPoint("TOPRIGHT", assignmentPanel, "TOPRIGHT", -12, -14)
    assignmentReadiness:SetJustifyH("RIGHT")
    assignmentReadiness:SetText("")
    assignmentReadiness:Hide()
    frame.assignmentReadiness = assignmentReadiness

    local memberHeader = CreateFrame("Frame", nil, membersPanel)
    memberHeader:SetPoint("TOPLEFT", 268, -340)
    memberHeader:SetSize(470, 18)
    frame.memberHeader = memberHeader

    local function MakeMemberHeader(parent, textValue, x, width, justify, sortKey, tooltipText)
      local widget
      if type(BuildBoardHeaderButton) == "function" and ((type(TrimText) == "function" and (TrimText(sortKey) ~= "" or TrimText(tooltipText) ~= "")) or type(TrimText) ~= "function") then
        widget = BuildBoardHeaderButton(frame, parent, textValue, sortKey, tooltipText or "", width, justify or "LEFT")
      else
        widget = parent:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        widget:SetWidth(width)
        widget:SetJustifyH(justify or "LEFT")
        widget:SetText(textValue)
      end
      widget:SetPoint("LEFT", x, 0)
      return widget
    end

    frame.memberHeaderName = MakeMemberHeader(memberHeader, "Raider", 8, 240, "LEFT", "name", "Character-Realm")
    frame.memberHeaderRoll = MakeMemberHeader(memberHeader, "Preference", 252, 110, "LEFT", "roll", "Selected roll option")
    frame.memberHeaderTotal = MakeMemberHeader(memberHeader, "Pts", 366, 52, "RIGHT", "total", "Total Points")
    frame.memberHeaderBis = MakeMemberHeader(memberHeader, "BiS", 424, 32, "RIGHT", "bis", "Received Best in Slot items")
    frame.memberHeaderDice = MakeMemberHeader(memberHeader, "Dice", 462, 42, "RIGHT", "dice", "Dice roll (1-100)")
    frame.memberHeaderOffSpec = MakeMemberHeader(memberHeader, "OS", 510, 28, "RIGHT", "offspec", "Off-Spec items")
    frame.memberHeaderTransmog = MakeMemberHeader(memberHeader, "TM", 544, 28, "RIGHT", "transmog", "Transmog items")
    frame.memberHeaderDisenchant = MakeMemberHeader(memberHeader, "DE", 578, 28, "RIGHT", "disenchant", "Disenchant items")
    frame.memberHeaderItems = MakeMemberHeader(memberHeader, "Items", 612, 38, "RIGHT", "items", "Received items")
    frame.memberHeaderState = MakeMemberHeader(memberHeader, "", 0, 1, "LEFT", "", "")
    frame.memberHeaderState:Hide()
    frame.memberHeaderVote = MakeMemberHeader(memberHeader, "Vote", 656, 50, "LEFT", "", "Cast or clear your vote")
    frame.memberHeaderVotes = MakeMemberHeader(memberHeader, "Votes", 710, 32, "RIGHT", "votes", "Number of votes")
    frame.__memberSortKey = "roll"
    frame.__memberSortDescending = false

    local memberScroll = CreateFrame("ScrollFrame", nil, membersPanel, "UIPanelScrollFrameTemplate")
    memberScroll:SetPoint("TOPLEFT", 268, -360)
    memberScroll:SetPoint("BOTTOMRIGHT", -24, 42)
    frame.memberListScroll = memberScroll

    local memberContent = CreateFrame("Frame", nil, memberScroll)
    memberContent:SetSize(500, 1)
    memberScroll:SetScrollChild(memberContent)
    frame.memberListContent = memberContent

    return frame
  end

  return {
    CreateBoardFrameScaffold = CreateBoardFrameScaffold,
  }
end
