local _, ns = ...
local L = ns.L or {}

local UIData = ns.UIData or {}
local THEME = UIData.THEME or {}
local STATUS_COLORS = UIData.STATUS_COLORS or {}
local UI_LAYOUT = UIData.UI_LAYOUT or {}
local WEEKLY_STATUS_ROW_HEIGHT = UIData.WEEKLY_STATUS_ROW_HEIGHT or 34
local WEEKLY_STATUS_ROW_GAP = UIData.WEEKLY_STATUS_ROW_GAP or 8

local UIHousingView = ns.UIHousingView or {}
local buildHousingEndeavorsView = UIHousingView.BuildEndeavorsView or function()
    return {
        available = false,
        message = L.HOUSING_UNAVAILABLE or "Housing data is not available yet.",
    }
end
local rememberHousingRenderError = UIHousingView.RememberRenderError or function() end
local housingTaskUI = UIHousingView.TaskUI or {}

local UIHousingCard = {}
ns.UIHousingCard = UIHousingCard

local function createHousingTaskRow(parent, helpers)
    local row = helpers.createWeeklyStatusRow(parent)
    row:SetHeight(UI_LAYOUT.housingTaskRowHeight)
    if row.statusBadge then
        row.statusBadge:Hide()
    end

    row.label:ClearAllPoints()
    row.label:SetPoint("TOPLEFT", 14, -8)
    row.label:SetPoint("BOTTOMRIGHT", row, "BOTTOMRIGHT", -96, 8)
    row.label:SetJustifyH("LEFT")
    row.label:SetJustifyV("TOP")
    if row.label.SetWordWrap then
        row.label:SetWordWrap(true)
    end

    row.value:ClearAllPoints()
    row.value:SetPoint("TOPRIGHT", -12, -9)
    row.value:SetWidth(86)
    row.value:SetJustifyH("RIGHT")
    row.value:SetJustifyV("TOP")
    if row.value.SetWordWrap then
        row.value:SetWordWrap(false)
    end
    if row.hitbox and row.hitbox.RegisterForClicks then
        row.hitbox:RegisterForClicks("LeftButtonUp")
        row.hitbox:SetScript("OnClick", function()
            if row.taskID == nil then
                return
            end

            housingTaskUI.toggle(row.taskID, row.taskTracked == true)
        end)
    end

    return row
end

local function applyHousingTaskRow(row, entry)
    if not row then
        return
    end

    if not entry then
        row.taskID = nil
        row.taskTracked = false
        row.tooltipTitle = nil
        row.tooltipLines = nil
        row:Hide()
        return
    end

    local color = STATUS_COLORS[entry.status or "missing"] or STATUS_COLORS.missing
    local titleText = type(entry.title) == "string" and entry.title or tostring(entry.title or "")
    local metaText = type(entry.meta) == "string" and entry.meta or tostring(entry.meta or "")
    local labelText = titleText
    if metaText ~= "" then
        labelText = labelText .. "\n" .. metaText
    end

    row.label:SetText(labelText)
    row.label:SetTextColor(THEME.parchment[1], THEME.parchment[2], THEME.parchment[3], 1)
    row.value:SetText(type(entry.statusText) == "string" and entry.statusText or tostring(entry.statusText or ""))
    row.value:SetTextColor(color[1], color[2], color[3], 1)
    row.statusLine:SetColorTexture(color[1], color[2], color[3], 0.95)
    if row.statusBadge then
        row.statusBadge:Hide()
    end
    row.taskID = entry.id
    row.taskTracked = entry.tracked == true
    row.tooltipTitle = entry.tooltipTitle
    row.tooltipLines = housingTaskUI.buildTooltipLines(entry)
    row:Show()
end

local function createHousingModeSidebar(parent, helpers)
    local createLabel = helpers.createLabel
    local createProgressBar = helpers.createProgressBar
    local createSectionFrame = helpers.createSectionFrame
    local createUtilityHeader = helpers.createUtilityHeader
    local createWeeklyStatusRow = helpers.createWeeklyStatusRow
    local styleScrollFrame = helpers.styleScrollFrame

    local panel = CreateFrame("Frame", nil, parent)
    panel:SetAllPoints(parent)
    panel:Hide()

    panel.title = createLabel(panel, "GameFontNormalLarge", "LEFT")
    panel.title:SetPoint("TOPLEFT", 16, -16)
    panel.title:SetText(L.MAIN_TAB_HOUSING or "Housing")

    panel.subtitle = createLabel(panel, "GameFontHighlightSmall", "LEFT")
    panel.subtitle:SetPoint("TOPLEFT", panel.title, "BOTTOMLEFT", 0, -8)
    panel.subtitle:SetPoint("TOPRIGHT", -16, 0)
    panel.subtitle:SetWordWrap(true)
    panel.subtitle:SetText(L.HOUSING_SECTION_HOME_SUBTITLE or "Active house, neighborhood, and house favor.")

    panel.emptyText = createLabel(panel, "GameFontDisable", "LEFT")
    panel.emptyText:SetPoint("TOPLEFT", panel.subtitle, "BOTTOMLEFT", 0, -14)
    panel.emptyText:SetPoint("BOTTOMRIGHT", -16, 16)
    panel.emptyText:SetJustifyV("TOP")
    panel.emptyText:SetWordWrap(true)
    panel.emptyText:Hide()

    panel.homeHeader = createUtilityHeader(panel, L.HOUSING_SECTION_HOME or "Home")
    panel.homeHeader:SetPoint("TOPLEFT", panel.subtitle, "BOTTOMLEFT", 0, -14)
    panel.homeHeader:SetPoint("TOPRIGHT", -16, 0)

    panel.homePanel = createSectionFrame(panel, "cardInset")
    panel.homePanel:SetPoint("TOPLEFT", panel.homeHeader, "BOTTOMLEFT", 0, -8)
    panel.homePanel:SetPoint("TOPRIGHT", panel.homeHeader, "TOPRIGHT", 0, -8)
    panel.homePanel:SetHeight(UI_LAYOUT.housingHomePanelHeight)

    panel.homeName = createLabel(panel.homePanel, "GameFontNormalLarge", "LEFT")
    panel.homeName:SetPoint("TOPLEFT", 14, -14)
    panel.homeName:SetPoint("TOPRIGHT", -14, -14)

    panel.homeSubtitle = createLabel(panel.homePanel, "GameFontHighlightSmall", "LEFT")
    panel.homeSubtitle:SetPoint("TOPLEFT", panel.homeName, "BOTTOMLEFT", 0, -6)
    panel.homeSubtitle:SetPoint("TOPRIGHT", -14, 0)
    panel.homeSubtitle:SetWordWrap(true)

    panel.homeMeta = createLabel(panel.homePanel, "GameFontDisableSmall", "LEFT")
    panel.homeMeta:SetPoint("TOPLEFT", panel.homeSubtitle, "BOTTOMLEFT", 0, -8)
    panel.homeMeta:SetPoint("TOPRIGHT", -14, 0)
    panel.homeMeta:SetWordWrap(true)

    panel.levelLabel = createLabel(panel.homePanel, "GameFontDisableSmall", "LEFT")
    panel.levelLabel:SetPoint("TOPLEFT", panel.homeMeta, "BOTTOMLEFT", 0, -12)
    panel.levelLabel:SetText(L.HOUSING_HOME_LEVEL or "Level")

    panel.levelValue = createLabel(panel.homePanel, "GameFontHighlightSmall", "RIGHT")
    panel.levelValue:SetPoint("RIGHT", -14, 0)
    panel.levelValue:SetPoint("CENTER", panel.levelLabel, "CENTER", 0, 0)

    panel.favorLabel = createLabel(panel.homePanel, "GameFontDisableSmall", "LEFT")
    panel.favorLabel:SetPoint("TOPLEFT", panel.levelLabel, "BOTTOMLEFT", 0, -16)
    panel.favorLabel:SetText(L.HOUSING_HOME_FAVOR or "House Favor")

    panel.favorValue = createLabel(panel.homePanel, "GameFontHighlightSmall", "RIGHT")
    panel.favorValue:SetPoint("RIGHT", -14, 0)
    panel.favorValue:SetPoint("CENTER", panel.favorLabel, "CENTER", 0, 0)

    panel.favorBar = createProgressBar(panel.homePanel)
    panel.favorBar:SetPoint("TOPLEFT", panel.favorLabel, "BOTTOMLEFT", 0, -8)
    panel.favorBar:SetPoint("TOPRIGHT", -14, 0)
    panel.favorBar:SetHeight(12)

    panel.couponLabel = createLabel(panel.homePanel, "GameFontDisableSmall", "LEFT")
    panel.couponLabel:SetPoint("TOPLEFT", panel.favorBar, "BOTTOMLEFT", 0, -16)
    panel.couponLabel:SetText(L.HOUSING_HOME_COUPONS or "Coupons")

    panel.couponValue = createLabel(panel.homePanel, "GameFontHighlightSmall", "RIGHT")
    panel.couponValue:SetPoint("RIGHT", -14, 0)
    panel.couponValue:SetPoint("CENTER", panel.couponLabel, "CENTER", 0, 0)

    panel.weeklyHeader = createUtilityHeader(panel, L.HOUSING_SECTION_WEEKLY or "Weekly")
    panel.weeklyHeader:SetPoint("TOPLEFT", panel.homePanel, "BOTTOMLEFT", 0, -16)
    panel.weeklyHeader:SetPoint("TOPRIGHT", -16, 0)

    panel.weeklyPanel = createSectionFrame(panel, "cardInset")
    panel.weeklyPanel:SetPoint("TOPLEFT", panel.weeklyHeader, "BOTTOMLEFT", 0, -8)
    panel.weeklyPanel:SetPoint("TOPRIGHT", panel.weeklyHeader, "TOPRIGHT", 0, -8)
    panel.weeklyPanel:SetHeight(54)

    panel.weeklyRow = createWeeklyStatusRow(panel.weeklyPanel)
    panel.weeklyRow:SetPoint("TOPLEFT", 14, -12)
    panel.weeklyRow:SetPoint("TOPRIGHT", -14, -12)

    panel.trackedHeader = createUtilityHeader(panel, L.HOUSING_SECTION_TRACKED or "Tracked Tasks")
    panel.trackedHeader:SetPoint("TOPLEFT", panel.weeklyPanel, "BOTTOMLEFT", 0, -16)
    panel.trackedHeader:SetPoint("TOPRIGHT", -16, 0)

    panel.trackedPanel = createSectionFrame(panel, "cardInset")
    panel.trackedPanel:SetPoint("TOPLEFT", panel.trackedHeader, "BOTTOMLEFT", 0, -8)
    panel.trackedPanel:SetPoint("BOTTOMRIGHT", -16, 16)

    panel.trackedPanel.subtitle = createLabel(panel.trackedPanel, "GameFontHighlightSmall", "LEFT")
    panel.trackedPanel.subtitle:SetPoint("TOPLEFT", 14, -14)
    panel.trackedPanel.subtitle:SetPoint("TOPRIGHT", -14, -14)
    panel.trackedPanel.subtitle:SetWordWrap(true)
    panel.trackedPanel.subtitle:SetText(L.HOUSING_SECTION_TRACKED_SUBTITLE or "Tasks currently pinned.")

    panel.trackedPanel.scroll = CreateFrame("ScrollFrame", nil, panel.trackedPanel, "UIPanelScrollFrameTemplate")
    panel.trackedPanel.scroll:SetPoint("TOPLEFT", panel.trackedPanel.subtitle, "BOTTOMLEFT", 0, -12)
    panel.trackedPanel.scroll:SetPoint("BOTTOMRIGHT", -24, 12)

    panel.trackedPanel.scrollChild = CreateFrame("Frame", nil, panel.trackedPanel.scroll)
    panel.trackedPanel.scrollChild:SetSize(214, 10)
    panel.trackedPanel.scroll:SetScrollChild(panel.trackedPanel.scrollChild)
    styleScrollFrame(panel.trackedPanel.scroll)

    panel.trackedPanel.empty = createLabel(panel.trackedPanel.scrollChild, "GameFontDisable", "LEFT")
    panel.trackedPanel.empty:SetPoint("TOPLEFT", 4, -4)
    panel.trackedPanel.empty:SetPoint("TOPRIGHT", -4, -4)
    panel.trackedPanel.empty:SetJustifyV("TOP")
    panel.trackedPanel.empty:SetWordWrap(true)
    panel.trackedPanel.empty:SetText(L.HOUSING_TRACKED_EMPTY or "No tracked housing tasks yet.")

    panel.trackedRows = {}
    return panel
end

local function createHousingModeCenter(parent, helpers)
    local createLabel = helpers.createLabel
    local createProgressBar = helpers.createProgressBar
    local createSectionFrame = helpers.createSectionFrame
    local createStatCard = helpers.createStatCard
    local styleScrollFrame = helpers.styleScrollFrame

    local card = CreateFrame("Frame", nil, parent)
    card:Hide()

    card.emptyText = createLabel(card, "GameFontDisableLarge", "LEFT")
    card.emptyText:SetPoint("TOPLEFT", 0, 0)
    card.emptyText:SetPoint("BOTTOMRIGHT", 0, 0)
    card.emptyText:SetJustifyV("TOP")
    card.emptyText:SetWordWrap(true)
    card.emptyText:Hide()

    card.summaryPanel = createSectionFrame(card, "card")
    card.summaryPanel:SetPoint("TOPLEFT", 0, 0)
    card.summaryPanel:SetPoint("TOPRIGHT", 0, 0)
    card.summaryPanel:SetHeight(UI_LAYOUT.housingSummaryPanelHeight)

    card.summaryPanel.title = createLabel(card.summaryPanel, "GameFontNormalLarge", "LEFT")
    card.summaryPanel.title:SetPoint("TOPLEFT", 14, -14)
    card.summaryPanel.title:SetText(L.HOUSING_TITLE or "Housing")

    card.summaryPanel.subtitle = createLabel(card.summaryPanel, "GameFontHighlightSmall", "LEFT")
    card.summaryPanel.subtitle:SetPoint("TOPLEFT", card.summaryPanel.title, "BOTTOMLEFT", 0, -6)
    card.summaryPanel.subtitle:SetPoint("TOPRIGHT", -14, 0)
    card.summaryPanel.subtitle:SetWordWrap(true)
    card.summaryPanel.subtitle:SetText("")
    card.summaryPanel.subtitle:Hide()

    card.statCards = {}
    for index = 1, 4 do
        local statCard = createStatCard(card.summaryPanel)
        statCard:Hide()
        card.statCards[index] = statCard
    end

    card.summaryPanel.progressLabel = createLabel(card.summaryPanel, "GameFontHighlightSmall", "LEFT")
    card.summaryPanel.progressLabel:SetText(L.HOUSING_PROGRESS_LABEL or "Endeavor Progress")

    card.summaryPanel.progressValue = createLabel(card.summaryPanel, "GameFontHighlightSmall", "RIGHT")
    card.summaryPanel.progressValue:SetText("")

    card.summaryPanel.progressBar = createProgressBar(card.summaryPanel)
    card.summaryPanel.progressBar:SetHeight(12)

    card.summaryPanel.note = createLabel(card.summaryPanel, "GameFontDisableSmall", "LEFT")
    card.summaryPanel.note:SetPoint("TOPLEFT", card.summaryPanel.progressBar, "BOTTOMLEFT", 0, -16)
    card.summaryPanel.note:SetPoint("TOPRIGHT", -14, 0)
    card.summaryPanel.note:SetWordWrap(true)

    card.tasksPanel = createSectionFrame(card, "cardInset")
    card.tasksPanel:SetPoint("TOPLEFT", card.summaryPanel, "BOTTOMLEFT", 0, -14)
    card.tasksPanel:SetPoint("BOTTOMRIGHT", 0, 0)

    card.tasksPanel.title = createLabel(card.tasksPanel, "GameFontNormalLarge", "LEFT")
    card.tasksPanel.title:SetPoint("TOPLEFT", 14, -14)
    card.tasksPanel.title:SetText(L.HOUSING_SECTION_TASKS or "Neighborhood Tasks")

    card.tasksPanel.subtitle = createLabel(card.tasksPanel, "GameFontHighlightSmall", "LEFT")
    card.tasksPanel.subtitle:SetPoint("TOPLEFT", card.tasksPanel.title, "BOTTOMLEFT", 0, -6)
    card.tasksPanel.subtitle:SetPoint("TOPRIGHT", -14, 0)
    card.tasksPanel.subtitle:SetWordWrap(true)
    card.tasksPanel.subtitle:SetText(L.HOUSING_SECTION_TASKS_SUBTITLE or "Current endeavor tasks with house XP, coupon rewards, and progress.")

    card.tasksPanel.scroll = CreateFrame("ScrollFrame", nil, card.tasksPanel, "UIPanelScrollFrameTemplate")
    card.tasksPanel.scroll:SetPoint("TOPLEFT", card.tasksPanel.subtitle, "BOTTOMLEFT", 0, -12)
    card.tasksPanel.scroll:SetPoint("BOTTOMRIGHT", -24, 12)

    card.tasksPanel.scrollChild = CreateFrame("Frame", nil, card.tasksPanel.scroll)
    card.tasksPanel.scrollChild:SetSize(520, 10)
    card.tasksPanel.scroll:SetScrollChild(card.tasksPanel.scrollChild)
    styleScrollFrame(card.tasksPanel.scroll)

    card.tasksPanel.empty = createLabel(card.tasksPanel.scrollChild, "GameFontDisable", "LEFT")
    card.tasksPanel.empty:SetPoint("TOPLEFT", 4, -4)
    card.tasksPanel.empty:SetPoint("TOPRIGHT", -4, -4)
    card.tasksPanel.empty:SetJustifyV("TOP")
    card.tasksPanel.empty:SetWordWrap(true)
    card.tasksPanel.empty:SetText(L.HOUSING_TASKS_EMPTY or "No neighborhood tasks found yet. Open the Housing dashboard once so Blizzard can populate the endeavor data.")

    card.taskRows = {}
    return card
end

local function createHousingModeUtility(parent, helpers)
    local createLabel = helpers.createLabel
    local createSectionFrame = helpers.createSectionFrame
    local createUtilityHeader = helpers.createUtilityHeader
    local styleScrollFrame = helpers.styleScrollFrame

    local panel = CreateFrame("Frame", nil, parent)
    panel:SetAllPoints(parent)
    panel:Hide()

    panel.title = createLabel(panel, "GameFontNormalLarge", "LEFT")
    panel.title:SetPoint("TOPLEFT", 16, -16)
    panel.title:SetText(L.HOUSING_UTILITY_TITLE or "Milestones & activity")

    panel.subtitle = createLabel(panel, "GameFontHighlightSmall", "LEFT")
    panel.subtitle:SetPoint("TOPLEFT", panel.title, "BOTTOMLEFT", 0, -8)
    panel.subtitle:SetPoint("TOPRIGHT", -16, 0)
    panel.subtitle:SetWordWrap(true)
    panel.subtitle:SetText(L.HOUSING_UTILITY_SUBTITLE or "Progress thresholds and the latest neighborhood contributions.")

    panel.emptyText = createLabel(panel, "GameFontDisable", "LEFT")
    panel.emptyText:SetPoint("TOPLEFT", panel.subtitle, "BOTTOMLEFT", 0, -14)
    panel.emptyText:SetPoint("BOTTOMRIGHT", -16, 16)
    panel.emptyText:SetJustifyV("TOP")
    panel.emptyText:SetWordWrap(true)
    panel.emptyText:Hide()

    panel.milestonesHeader = createUtilityHeader(panel, L.HOUSING_SECTION_MILESTONES or "Milestones")
    panel.milestonesHeader:SetPoint("TOPLEFT", panel.subtitle, "BOTTOMLEFT", 0, -14)
    panel.milestonesHeader:SetPoint("TOPRIGHT", -16, 0)

    panel.milestonesPanel = createSectionFrame(panel, "cardInset")
    panel.milestonesPanel:SetPoint("TOPLEFT", panel.milestonesHeader, "BOTTOMLEFT", 0, -8)
    panel.milestonesPanel:SetPoint("TOPRIGHT", panel.milestonesHeader, "TOPRIGHT", 0, -8)
    panel.milestonesPanel:SetHeight(UI_LAYOUT.housingMilestonesPanelHeight)

    panel.milestonesPanel.subtitle = createLabel(panel.milestonesPanel, "GameFontHighlightSmall", "LEFT")
    panel.milestonesPanel.subtitle:SetPoint("TOPLEFT", 14, -14)
    panel.milestonesPanel.subtitle:SetPoint("TOPRIGHT", -14, -14)
    panel.milestonesPanel.subtitle:SetWordWrap(true)
    panel.milestonesPanel.subtitle:SetText(L.HOUSING_SECTION_MILESTONES_SUBTITLE or "Progress thresholds for the current neighborhood endeavor.")

    panel.milestonesPanel.scroll = CreateFrame("ScrollFrame", nil, panel.milestonesPanel, "UIPanelScrollFrameTemplate")
    panel.milestonesPanel.scroll:SetPoint("TOPLEFT", panel.milestonesPanel.subtitle, "BOTTOMLEFT", 0, -12)
    panel.milestonesPanel.scroll:SetPoint("BOTTOMRIGHT", -24, 12)

    panel.milestonesPanel.scrollChild = CreateFrame("Frame", nil, panel.milestonesPanel.scroll)
    panel.milestonesPanel.scrollChild:SetSize(250, 10)
    panel.milestonesPanel.scroll:SetScrollChild(panel.milestonesPanel.scrollChild)
    styleScrollFrame(panel.milestonesPanel.scroll)

    panel.milestonesPanel.empty = createLabel(panel.milestonesPanel.scrollChild, "GameFontDisable", "LEFT")
    panel.milestonesPanel.empty:SetPoint("TOPLEFT", 4, -4)
    panel.milestonesPanel.empty:SetPoint("TOPRIGHT", -4, -4)
    panel.milestonesPanel.empty:SetJustifyV("TOP")
    panel.milestonesPanel.empty:SetWordWrap(true)
    panel.milestonesPanel.empty:SetText(L.HOUSING_MILESTONES_EMPTY or "No milestones available yet.")

    panel.activityHeader = createUtilityHeader(panel, L.HOUSING_SECTION_ACTIVITY or "Recent Activity")
    panel.activityHeader:SetPoint("TOPLEFT", panel.milestonesPanel, "BOTTOMLEFT", 0, -16)
    panel.activityHeader:SetPoint("TOPRIGHT", -16, 0)

    panel.activityPanel = createSectionFrame(panel, "cardInset")
    panel.activityPanel:SetPoint("TOPLEFT", panel.activityHeader, "BOTTOMLEFT", 0, -8)
    panel.activityPanel:SetPoint("BOTTOMRIGHT", -16, 16)

    panel.activityPanel.subtitle = createLabel(panel.activityPanel, "GameFontHighlightSmall", "LEFT")
    panel.activityPanel.subtitle:SetPoint("TOPLEFT", 14, -14)
    panel.activityPanel.subtitle:SetPoint("TOPRIGHT", -14, -14)
    panel.activityPanel.subtitle:SetWordWrap(true)
    panel.activityPanel.subtitle:SetText(L.HOUSING_SECTION_ACTIVITY_SUBTITLE or "Latest recorded neighborhood contributions from the activity feed.")

    panel.activityPanel.scroll = CreateFrame("ScrollFrame", nil, panel.activityPanel, "UIPanelScrollFrameTemplate")
    panel.activityPanel.scroll:SetPoint("TOPLEFT", panel.activityPanel.subtitle, "BOTTOMLEFT", 0, -12)
    panel.activityPanel.scroll:SetPoint("BOTTOMRIGHT", -24, 12)

    panel.activityPanel.scrollChild = CreateFrame("Frame", nil, panel.activityPanel.scroll)
    panel.activityPanel.scrollChild:SetSize(250, 10)
    panel.activityPanel.scroll:SetScrollChild(panel.activityPanel.scrollChild)
    styleScrollFrame(panel.activityPanel.scroll)

    panel.activityPanel.empty = createLabel(panel.activityPanel.scrollChild, "GameFontDisable", "LEFT")
    panel.activityPanel.empty:SetPoint("TOPLEFT", 4, -4)
    panel.activityPanel.empty:SetPoint("TOPRIGHT", -4, -4)
    panel.activityPanel.empty:SetJustifyV("TOP")
    panel.activityPanel.empty:SetWordWrap(true)
    panel.activityPanel.empty:SetText(L.HOUSING_ACTIVITY_EMPTY or "No recent housing activity recorded yet.")

    panel.milestoneRows = {}
    panel.activityRows = {}
    return panel
end

local function ensureHousingTrackedRows(ui, count, helpers)
    if not ui.frame or not ui.frame.housingSidebar then
        return
    end

    local sidebar = ui.frame.housingSidebar
    while #sidebar.trackedRows < count do
        local row = helpers.createWeeklyStatusRow(sidebar.trackedPanel.scrollChild)
        local index = #sidebar.trackedRows + 1
        if index == 1 then
            row:SetPoint("TOPLEFT", 0, 0)
            row:SetPoint("TOPRIGHT", 0, 0)
        else
            row:SetPoint("TOPLEFT", sidebar.trackedRows[index - 1], "BOTTOMLEFT", 0, -8)
            row:SetPoint("TOPRIGHT", sidebar.trackedRows[index - 1], "BOTTOMRIGHT", 0, -8)
        end
        if row.hitbox and row.hitbox.RegisterForClicks then
            row.hitbox:RegisterForClicks("LeftButtonUp")
            row.hitbox:SetScript("OnClick", function()
                if row.taskID == nil then
                    return
                end

                housingTaskUI.toggle(row.taskID, row.taskTracked == true)
            end)
        end
        row:Hide()
        sidebar.trackedRows[index] = row
    end
end

local function ensureHousingTaskRows(ui, count, helpers)
    if not ui.frame or not ui.frame.housingCenter then
        return
    end

    local center = ui.frame.housingCenter
    while #center.taskRows < count do
        local row = createHousingTaskRow(center.tasksPanel.scrollChild, helpers)
        local index = #center.taskRows + 1
        if index == 1 then
            row:SetPoint("TOPLEFT", 0, 0)
            row:SetPoint("TOPRIGHT", 0, 0)
        else
            row:SetPoint("TOPLEFT", center.taskRows[index - 1], "BOTTOMLEFT", 0, -UI_LAYOUT.housingTaskRowGap)
            row:SetPoint("TOPRIGHT", center.taskRows[index - 1], "BOTTOMRIGHT", 0, -UI_LAYOUT.housingTaskRowGap)
        end
        row:Hide()
        center.taskRows[index] = row
    end
end

local function ensureHousingMilestoneRows(ui, count, helpers)
    if not ui.frame or not ui.frame.housingUtility then
        return
    end

    local utility = ui.frame.housingUtility
    while #utility.milestoneRows < count do
        local row = helpers.createWeeklyStatusRow(utility.milestonesPanel.scrollChild)
        local index = #utility.milestoneRows + 1
        if index == 1 then
            row:SetPoint("TOPLEFT", 0, 0)
            row:SetPoint("TOPRIGHT", 0, 0)
        else
            row:SetPoint("TOPLEFT", utility.milestoneRows[index - 1], "BOTTOMLEFT", 0, -8)
            row:SetPoint("TOPRIGHT", utility.milestoneRows[index - 1], "BOTTOMRIGHT", 0, -8)
        end
        row:Hide()
        utility.milestoneRows[index] = row
    end
end

local function ensureHousingActivityRows(ui, count, helpers)
    if not ui.frame or not ui.frame.housingUtility then
        return
    end

    local utility = ui.frame.housingUtility
    while #utility.activityRows < count do
        local row = helpers.createWeeklyStatusRow(utility.activityPanel.scrollChild)
        local index = #utility.activityRows + 1
        if index == 1 then
            row:SetPoint("TOPLEFT", 0, 0)
            row:SetPoint("TOPRIGHT", 0, 0)
        else
            row:SetPoint("TOPLEFT", utility.activityRows[index - 1], "BOTTOMLEFT", 0, -8)
            row:SetPoint("TOPRIGHT", utility.activityRows[index - 1], "BOTTOMRIGHT", 0, -8)
        end
        row:Hide()
        utility.activityRows[index] = row
    end
end

local function layoutHousingCard(ui)
    if not ui.frame then
        return
    end

    local center = ui.frame.housingCenter
    if center and center.summaryPanel then
        local gap = 12
        local statHeight = UI_LAYOUT.housingStatCardHeight
        local innerWidth = math.max(520, (center.summaryPanel:GetWidth() or 0) - 28)
        local statCount = math.max(1, #(center.statCards or {}))
        local statWidth = math.floor((innerWidth - (gap * (statCount - 1))) / statCount)
        statWidth = math.max(112, statWidth)

        local statsAnchor = (center.summaryPanel.subtitle and center.summaryPanel.subtitle:IsShown())
            and center.summaryPanel.subtitle
            or center.summaryPanel.title
        local statsOffset = (center.summaryPanel.subtitle and center.summaryPanel.subtitle:IsShown()) and -12 or -18

        for index, statCard in ipairs(center.statCards or {}) do
            statCard:ClearAllPoints()
            statCard:SetSize(statWidth, statHeight)
            if index == 1 then
                statCard:SetPoint("TOPLEFT", statsAnchor, "BOTTOMLEFT", 0, statsOffset)
            else
                statCard:SetPoint("TOPLEFT", center.statCards[index - 1], "TOPRIGHT", gap, 0)
            end
        end

        center.summaryPanel.progressLabel:ClearAllPoints()
        center.summaryPanel.progressLabel:SetPoint("TOPLEFT", center.statCards[1], "BOTTOMLEFT", 0, -16)

        center.summaryPanel.progressValue:ClearAllPoints()
        center.summaryPanel.progressValue:SetPoint("RIGHT", -14, 0)
        center.summaryPanel.progressValue:SetPoint("CENTER", center.summaryPanel.progressLabel, "CENTER", 0, 0)

        center.summaryPanel.progressBar:ClearAllPoints()
        center.summaryPanel.progressBar:SetPoint("TOPLEFT", center.summaryPanel.progressLabel, "BOTTOMLEFT", 0, -8)
        center.summaryPanel.progressBar:SetPoint("TOPRIGHT", -14, 0)

        if center.tasksPanel and center.tasksPanel.scrollChild then
            local taskWidth = math.max(100, math.floor(center.tasksPanel.scroll:GetWidth() or (center.tasksPanel:GetWidth() - 34)))
            center.tasksPanel.scrollChild:SetWidth(taskWidth)
        end
    end

    local sidebar = ui.frame.housingSidebar
    if sidebar and sidebar.trackedPanel and sidebar.trackedPanel.scrollChild then
        local trackedWidth = math.max(100, math.floor(sidebar.trackedPanel.scroll:GetWidth() or (sidebar.trackedPanel:GetWidth() - 34)))
        sidebar.trackedPanel.scrollChild:SetWidth(trackedWidth)
    end

    local utility = ui.frame.housingUtility
    if utility and utility.milestonesPanel and utility.milestonesPanel.scrollChild then
        local milestoneWidth = math.max(100, math.floor(utility.milestonesPanel.scroll:GetWidth() or (utility.milestonesPanel:GetWidth() - 34)))
        utility.milestonesPanel.scrollChild:SetWidth(milestoneWidth)
    end
    if utility and utility.activityPanel and utility.activityPanel.scrollChild then
        local activityWidth = math.max(100, math.floor(utility.activityPanel.scroll:GetWidth() or (utility.activityPanel:GetWidth() - 34)))
        utility.activityPanel.scrollChild:SetWidth(activityWidth)
    end
end

local function refreshHousingCard(ui, character, view, helpers)
    if not ui.frame or not ui.frame.housingSidebar or not ui.frame.housingCenter or not ui.frame.housingUtility then
        return
    end

    local sidebar = ui.frame.housingSidebar
    local center = ui.frame.housingCenter
    local utility = ui.frame.housingUtility
    layoutHousingCard(ui)

    view = view or buildHousingEndeavorsView(character)
    if not (view and view.available) then
        local message = (view and view.message) or (L.HOUSING_UNAVAILABLE or "Housing data is not available yet.")

        sidebar.title:SetText(L.MAIN_TAB_HOUSING or "Housing")
        sidebar.subtitle:SetText(L.HOUSING_SECTION_HOME_SUBTITLE or "Active house, neighborhood, and house progress.")
        sidebar.emptyText:SetText(message)
        sidebar.emptyText:Show()
        sidebar.homeHeader:Hide()
        sidebar.homePanel:Hide()
        sidebar.weeklyHeader:Hide()
        sidebar.weeklyPanel:Hide()
        sidebar.trackedHeader:Hide()
        sidebar.trackedPanel:Hide()
        sidebar.weeklyRow:Hide()
        for _, row in ipairs(sidebar.trackedRows or {}) do
            row:Hide()
        end

        center.emptyText:SetText(message)
        center.emptyText:Show()
        center.summaryPanel:Hide()
        center.tasksPanel:Hide()
        for _, statCard in ipairs(center.statCards or {}) do
            statCard:Hide()
        end
        for _, row in ipairs(center.taskRows or {}) do
            row:Hide()
        end

        utility.title:SetText(L.HOUSING_UTILITY_TITLE or "Milestones & activity")
        utility.subtitle:SetText(L.HOUSING_UTILITY_SUBTITLE or "Progress thresholds and the latest neighborhood contributions.")
        utility.emptyText:SetText(message)
        utility.emptyText:Show()
        utility.milestonesHeader:Hide()
        utility.milestonesPanel:Hide()
        utility.activityHeader:Hide()
        utility.activityPanel:Hide()
        for _, row in ipairs(utility.milestoneRows or {}) do
            row:Hide()
        end
        for _, row in ipairs(utility.activityRows or {}) do
            row:Hide()
        end
        return
    end

    sidebar.title:SetText(L.MAIN_TAB_HOUSING or "Housing")
    sidebar.subtitle:SetText(L.HOUSING_SECTION_HOME_SUBTITLE or "Active house, neighborhood, and house progress.")
    sidebar.emptyText:Hide()
    sidebar.homeHeader:Show()
    sidebar.homePanel:Show()
    sidebar.weeklyHeader:Show()
    sidebar.weeklyPanel:Show()
    sidebar.trackedHeader:Show()
    sidebar.trackedPanel:Show()

    sidebar.homeName:SetText(view.house and view.house.title or (L.HOUSING_HOME_NONE or "No house data yet"))
    sidebar.homeSubtitle:SetText(view.house and view.house.subtitle or "")
    sidebar.homeSubtitle:SetShown(type(view.house and view.house.subtitle) == "string" and view.house.subtitle ~= "")
    sidebar.homeMeta:SetText(view.house and view.house.meta or "")
    sidebar.levelLabel:SetText(L.HOUSING_HOME_LEVEL or "Level")
    sidebar.levelValue:SetText(view.house and view.house.levelValue or "--")
    sidebar.favorLabel:SetText(L.HOUSING_HOME_FAVOR or "House Progress")
    sidebar.favorValue:SetText(view.house and view.house.favorValue or "--")
    sidebar.couponLabel:SetText(view.house and view.house.couponLabel or (L.HOUSING_HOME_COUPONS or "Coupons"))
    sidebar.couponValue:SetText(view.house and view.house.couponValue or "--")
    helpers.setProgressBar(sidebar.favorBar, view.house and view.house.favorRatio or 0, THEME.gold[1], THEME.gold[2], THEME.gold[3])

    helpers.setHousingSidebarStatusRow(
        sidebar.weeklyRow,
        view.weekly or {
            label = L.PVE_WEEKLY_ROW_HOUSING or "Housing Weekly",
            text = L.STATUS_MISSING or "Accept",
            status = "missing",
            tooltipTitle = L.PVE_WEEKLY_ROW_HOUSING or "Housing Weekly",
            tooltipLines = {
                L.PVE_WEEKLY_HOUSING_ACCEPT_HINT or "This quest can be accepted from Vaeli in Silvermoon.",
            },
        }
    )

    local trackedEntries = type(view.trackedTasks) == "table" and view.trackedTasks or {}
    ensureHousingTrackedRows(ui, #trackedEntries, helpers)
    for index, row in ipairs(sidebar.trackedRows or {}) do
        local entry = trackedEntries[index]
        if entry then
            helpers.setHousingSidebarStatusRow(row, entry)
            row.taskID = entry.id
            row.taskTracked = entry.tracked == true
            row.tooltipLines = housingTaskUI.buildTooltipLines(entry)
        else
            row.taskID = nil
            row.taskTracked = false
            row.tooltipTitle = nil
            row.tooltipLines = nil
            row:Hide()
        end
    end
    sidebar.trackedPanel.scrollChild:SetHeight(math.max(
        10,
        (#trackedEntries * (WEEKLY_STATUS_ROW_HEIGHT + WEEKLY_STATUS_ROW_GAP)) - WEEKLY_STATUS_ROW_GAP,
        (#trackedEntries == 0 and 110 or 0)
    ))
    sidebar.trackedPanel.empty:SetShown(#trackedEntries == 0)

    center.emptyText:Hide()
    center.summaryPanel:Show()
    center.tasksPanel:Show()
    center.summaryPanel.title:SetText(view.title or (L.HOUSING_TITLE or "Housing"))
    center.summaryPanel.subtitle:SetText(view.subtitle or "")
    center.summaryPanel.subtitle:SetShown(type(view.subtitle) == "string" and view.subtitle ~= "")
    center.summaryPanel.progressLabel:SetText((view.progress and view.progress.label) or (L.HOUSING_PROGRESS_LABEL or "Endeavor Progress"))
    center.summaryPanel.progressValue:SetText((view.progress and view.progress.value) or "--")
    helpers.setProgressBar(
        center.summaryPanel.progressBar,
        view.progress and view.progress.ratio or 0,
        THEME.gold[1],
        THEME.gold[2],
        THEME.gold[3]
    )
    helpers.setProgressBreakpoints(
        center.summaryPanel.progressBar,
        view.progress and view.progress.thresholds or nil,
        view.progress and view.progress.maxThreshold or 0
    )
    center.summaryPanel.note:SetText(view.progress and view.progress.note or "")
    center.summaryPanel.note:SetShown(type(view.progress and view.progress.note) == "string" and view.progress.note ~= "")

    for index, statCard in ipairs(center.statCards or {}) do
        local entry = view.statCards and view.statCards[index] or nil
        if entry then
            helpers.applyStatCard(statCard, entry)
            statCard:Show()
        else
            statCard:Hide()
        end
    end

    local taskEntries = type(view.tasks) == "table" and view.tasks or {}
    local previousTaskCount = tonumber(ui._housingTaskRowCount) or 0
    local okTaskRender, taskRenderError = xpcall(function()
        ensureHousingTaskRows(ui, #taskEntries, helpers)
        for index, row in ipairs(center.taskRows or {}) do
            local entry = taskEntries[index]
            if entry then
                applyHousingTaskRow(row, entry)
            else
                row:Hide()
            end
        end
        center.tasksPanel.scrollChild:SetHeight(math.max(
            10,
            (#taskEntries * (UI_LAYOUT.housingTaskRowHeight + UI_LAYOUT.housingTaskRowGap)) - UI_LAYOUT.housingTaskRowGap,
            (#taskEntries == 0 and 130 or 0)
        ))
        center.tasksPanel.empty:SetText(
            (view.loadingTasks and (L.HOUSING_LOADING or "Housing data is loading. Give the game a moment to deliver house and neighborhood information."))
                or (L.HOUSING_TASKS_EMPTY or "No neighborhood tasks found yet. Open the Housing dashboard once so Blizzard can populate the endeavor data.")
        )
        center.tasksPanel.empty:SetShown(#taskEntries == 0)
        helpers.clampScrollFramePosition(center.tasksPanel.scroll, previousTaskCount == 0 and #taskEntries > 0)
        ui._housingTaskRowCount = #taskEntries
    end, function(err)
        return tostring(err or "unknown task render error")
    end)
    if okTaskRender then
        rememberHousingRenderError(nil)
    else
        rememberHousingRenderError("tasks", taskRenderError)
        for _, row in ipairs(center.taskRows or {}) do
            row:Hide()
        end
        center.tasksPanel.scrollChild:SetHeight(130)
        center.tasksPanel.empty:SetText("Housing tasks could not be drawn. Please reload and try again.")
        center.tasksPanel.empty:Show()
        ui._housingTaskRowCount = 0
    end

    utility.title:SetText(L.HOUSING_UTILITY_TITLE or "Milestones & activity")
    utility.subtitle:SetText(L.HOUSING_UTILITY_SUBTITLE or "Progress thresholds and the latest neighborhood contributions.")
    utility.emptyText:Hide()
    utility.milestonesHeader:Show()
    utility.milestonesPanel:Show()
    utility.activityHeader:Show()
    utility.activityPanel:Show()

    local milestoneEntries = type(view.milestones) == "table" and view.milestones or {}
    local previousMilestoneCount = tonumber(ui._housingMilestoneRowCount) or 0
    ensureHousingMilestoneRows(ui, #milestoneEntries, helpers)
    for index, row in ipairs(utility.milestoneRows or {}) do
        local entry = milestoneEntries[index]
        if entry then
            helpers.setStatusRowWithoutBadge(row, entry)
        else
            row:Hide()
        end
    end
    utility.milestonesPanel.scrollChild:SetHeight(math.max(
        10,
        (#milestoneEntries * (WEEKLY_STATUS_ROW_HEIGHT + WEEKLY_STATUS_ROW_GAP)) - WEEKLY_STATUS_ROW_GAP,
        (#milestoneEntries == 0 and 100 or 0)
    ))
    utility.milestonesPanel.empty:SetShown(#milestoneEntries == 0)
    helpers.clampScrollFramePosition(utility.milestonesPanel.scroll, previousMilestoneCount == 0 and #milestoneEntries > 0)
    ui._housingMilestoneRowCount = #milestoneEntries

    local activityEntries = type(view.activity) == "table" and view.activity or {}
    local previousActivityCount = tonumber(ui._housingActivityRowCount) or 0
    ensureHousingActivityRows(ui, #activityEntries, helpers)
    for index, row in ipairs(utility.activityRows or {}) do
        local entry = activityEntries[index]
        if entry then
            helpers.setStatusRowWithoutBadge(row, entry)
        else
            row:Hide()
        end
    end
    utility.activityPanel.scrollChild:SetHeight(math.max(
        10,
        (#activityEntries * (WEEKLY_STATUS_ROW_HEIGHT + WEEKLY_STATUS_ROW_GAP)) - WEEKLY_STATUS_ROW_GAP,
        (#activityEntries == 0 and 100 or 0)
    ))
    utility.activityPanel.empty:SetShown(#activityEntries == 0)
    helpers.clampScrollFramePosition(utility.activityPanel.scroll, previousActivityCount == 0 and #activityEntries > 0)
    ui._housingActivityRowCount = #activityEntries

    layoutHousingCard(ui)
end

UIHousingCard.CreateTaskRow = createHousingTaskRow
UIHousingCard.ApplyTaskRow = applyHousingTaskRow
UIHousingCard.CreateModeSidebar = createHousingModeSidebar
UIHousingCard.CreateModeCenter = createHousingModeCenter
UIHousingCard.CreateModeUtility = createHousingModeUtility
UIHousingCard.EnsureTrackedRows = ensureHousingTrackedRows
UIHousingCard.EnsureTaskRows = ensureHousingTaskRows
UIHousingCard.EnsureMilestoneRows = ensureHousingMilestoneRows
UIHousingCard.EnsureActivityRows = ensureHousingActivityRows
UIHousingCard.Layout = layoutHousingCard
UIHousingCard.Refresh = refreshHousingCard
