-- ============================================================================
-- Vamoose's Endeavors - MainFrame
-- Main window creation and management with tab switching
-- ============================================================================

VE = VE or {}

-- ============================================================================
-- WINDOW POSITION PERSISTENCE
-- ============================================================================

local function SaveWindowPosition(frame)
    if not frame then return end
    local point, _, relPoint, x, y = frame:GetPoint()
    VE_DB = VE_DB or {}
    VE_DB.windowPos = {
        point = point,
        relPoint = relPoint,
        x = x,
        y = y,
    }
end

local function RestoreWindowPosition(frame)
    if not frame then return end
    if VE_DB and VE_DB.windowPos then
        local pos = VE_DB.windowPos
        frame:ClearAllPoints()
        frame:SetPoint(pos.point, UIParent, pos.relPoint, pos.x, pos.y)
    end
end

-- ============================================================================
-- MAIN WINDOW CREATION
-- ============================================================================

function VE:CreateMainWindow()
    if self.MainFrame then return self.MainFrame end

    local version = C_AddOns.GetAddOnMetadata("VamoosesEndeavors", "Version") or "Dev"
    local frame = VE.UI:CreateMainFrame("VE_MainFrame", "Vamoose's Endeavors v" .. version)
    frame:Hide()

    -- Restore saved position
    RestoreWindowPosition(frame)

    -- Apply saved UI scale
    local uiScale = VE.Store:GetState().config.uiScale or 1.0
    frame:SetScale(uiScale)

    -- Save position on drag stop
    frame:HookScript("OnDragStop", function(self)
        SaveWindowPosition(self)
    end)

    -- ========================================================================
    -- TAB BAR
    -- ========================================================================

    local tabBar = CreateFrame("Frame", nil, frame)
    local uiConsts = VE.Constants.UI or {}
    tabBar:SetHeight(uiConsts.tabHeight or 24)
    tabBar:SetPoint("TOPLEFT", 0, -uiConsts.titleBarHeight)
    tabBar:SetPoint("TOPRIGHT", 0, -uiConsts.titleBarHeight)
    frame.tabBar = tabBar

    -- Tab bar background (atlas for Housing Theme)
    local tabBarBg = tabBar:CreateTexture(nil, "BACKGROUND")
    tabBarBg:SetAllPoints()
    local Colors = VE.Constants:GetThemeColors()
    if Colors.atlas and Colors.atlas.tabSectionBg then
        tabBarBg:SetAtlas(Colors.atlas.tabSectionBg)
    else
        tabBarBg:SetTexture("Interface\\Buttons\\WHITE8x8")
        tabBarBg:SetVertexColor(0, 0, 0, 0)  -- Transparent for non-atlas themes
    end
    tabBar.bg = tabBarBg
    VE.Theme:Register(tabBar, "TabBar")

    -- Create tab buttons (via factory method with Theme Engine registration)
    -- Calculate equal tab width: (window width - 2 * padding) / num tabs
    local PADDING = 4
    local NUM_TABS = 4
    local tabWidth = math.floor((uiConsts.mainWidth - (2 * PADDING)) / NUM_TABS)

    local endeavorsTabBtn = VE.UI:CreateTabButton(tabBar, "Endeavors")
    endeavorsTabBtn:SetSize(tabWidth, uiConsts.tabHeight or 24)
    endeavorsTabBtn:SetPoint("LEFT", PADDING, 0)

    local leaderboardTabBtn = VE.UI:CreateTabButton(tabBar, "Rankings")
    leaderboardTabBtn:SetSize(tabWidth, uiConsts.tabHeight or 24)
    leaderboardTabBtn:SetPoint("LEFT", endeavorsTabBtn, "RIGHT", 0, 0)

    local activityTabBtn = VE.UI:CreateTabButton(tabBar, "Activity")
    activityTabBtn:SetSize(tabWidth, uiConsts.tabHeight or 24)
    activityTabBtn:SetPoint("LEFT", leaderboardTabBtn, "RIGHT", 0, 0)

    local configTabBtn = VE.UI:CreateTabButton(tabBar, "Config")
    configTabBtn:SetSize(tabWidth, uiConsts.tabHeight or 24)
    configTabBtn:SetPoint("LEFT", activityTabBtn, "RIGHT", 0, 0)

    frame.endeavorsTabBtn = endeavorsTabBtn
    frame.leaderboardTabBtn = leaderboardTabBtn
    frame.activityTabBtn = activityTabBtn
    frame.configTabBtn = configTabBtn

    -- Update housing display (coupons + house level) from Store
    function frame:UpdateHousingDisplay()
        local state = VE.Store:GetState()
        local housing = state.housing
        local C = VE.Constants:GetThemeColors()

        -- Update coupons
        if housing.coupons and housing.coupons > 0 then
            if housing.couponsIcon then
                self.couponsIcon:SetTexture(housing.couponsIcon)
            end
            self.couponsText:SetText(housing.coupons)
            self.couponsIcon:Show()
            self.couponsText:Show()
        else
            -- Fallback to direct API call if Store not populated yet
            local currencyInfo = C_CurrencyInfo.GetCurrencyInfo(VE.Constants.CURRENCY_IDS.COMMUNITY_COUPONS)
            if currencyInfo and currencyInfo.quantity then
                self.couponsIcon:SetTexture(currencyInfo.iconFileID)
                self.couponsText:SetText(currencyInfo.quantity)
                self.couponsIcon:Show()
                self.couponsText:Show()
            else
                self.couponsIcon:Hide()
                self.couponsText:Hide()
            end
        end

        -- Update house level
        local level = housing.level or 0
        local xp = housing.xp or 0
        local xpForNextLevel = housing.xpForNextLevel or 0
        local maxLevel = housing.maxLevel or 50

        if level > 0 then
            -- Generate hex from RGB for current theme colors
            local accentHex = string.format("%02x%02x%02x", math.floor(C.accent.r * 255), math.floor(C.accent.g * 255), math.floor(C.accent.b * 255))
            local dimHex = string.format("%02x%02x%02x", math.floor(C.text_dim.r * 255), math.floor(C.text_dim.g * 255), math.floor(C.text_dim.b * 255))
            local houseIcon = "|A:housing-map-plot-occupied-highlight:12:12|a"
            if level >= maxLevel then
                self.houseLevelText:SetText(string.format("%s |cFF%sLv %d|r |cFF%s(Max)|r", houseIcon, accentHex, level, dimHex))
            else
                self.houseLevelText:SetText(string.format("%s |cFF%sLv %d|r |cFF%s%d/%d XP|r", houseIcon, accentHex, level, dimHex, xp, xpForNextLevel))
            end
        else
            self.houseLevelText:SetText("")
        end
    end

    -- Legacy alias for UpdateCoupons
    frame.UpdateCoupons = frame.UpdateHousingDisplay

    -- ========================================================================
    -- PERSISTENT HEADER (always visible, even when minimized)
    -- ========================================================================

    local UI = VE.Constants.UI
    local C = VE.Constants.Colors
    local padding = UI.panelPadding

    local headerSection = CreateFrame("Frame", nil, frame)
    headerSection:SetHeight(UI.headerSectionHeight)
    local headerOffset = -(UI.titleBarHeight + UI.tabHeight)
    headerSection:SetPoint("TOPLEFT", padding, headerOffset)
    headerSection:SetPoint("TOPRIGHT", -padding, headerOffset)
    frame.headerSection = headerSection

    -- Atlas background will be positioned after rows are created
    local headerBg = headerSection:CreateTexture(nil, "BACKGROUND")
    headerBg:SetAtlas("housing-basic-panel--stone-background")
    headerSection.atlasBg = headerBg
    VE.Theme:Register(headerSection, "HeaderSection")

    -- Season name (top left)
    local seasonName = headerSection:CreateFontString(nil, "OVERLAY")
    seasonName:SetPoint("TOPLEFT", 2, -2)
    VE.Theme.ApplyFont(seasonName, C)
    seasonName:SetTextColor(C.text.r, C.text.g, C.text.b)
    seasonName._colorType = "text"
    VE.Theme:Register(seasonName, "HeaderText")
    frame.seasonName = seasonName

    -- Days remaining (top right)
    local daysRemaining = headerSection:CreateFontString(nil, "OVERLAY")
    daysRemaining:SetPoint("TOPRIGHT", 0, -2)
    VE.Theme.ApplyFont(daysRemaining, C, "small")
    daysRemaining:SetTextColor(C.text_dim.r, C.text_dim.g, C.text_dim.b)
    daysRemaining._colorType = "text_dim"
    VE.Theme:Register(daysRemaining, "HeaderText")
    frame.daysRemaining = daysRemaining

    -- Progress bar (full width, below season name)
    local progressBar = VE.UI:CreateProgressBar(headerSection, {
        width = 100,
        height = UI.progressBarHeight,
    })
    progressBar:SetPoint("TOPLEFT", seasonName, "BOTTOMLEFT", 0, -4)
    progressBar:SetPoint("TOPRIGHT", 0, 0)
    frame.progressBar = progressBar

    -- ========================================================================
    -- ROW 1: Dropdown (left), House Level + XP (right) / Fetch Status (right)
    -- ========================================================================
    local dropdownRow = CreateFrame("Frame", nil, headerSection)
    dropdownRow:SetHeight(20)
    dropdownRow:SetPoint("TOPLEFT", progressBar, "BOTTOMLEFT", 0, -4)
    dropdownRow:SetPoint("TOPRIGHT", progressBar, "BOTTOMRIGHT", 0, -4)

    -- House icon (left side)
    local houseIcon = dropdownRow:CreateTexture(nil, "ARTWORK")
    houseIcon:SetSize(16, 16)
    houseIcon:SetPoint("LEFT", 3, 0)
    houseIcon:SetAtlas("housefinder_main-icon")
    frame.houseIcon = houseIcon

    -- House selector dropdown (after icon) - uses custom styled dropdown
    local houseDropdown = VE.UI:CreateDropdown(dropdownRow, {
        width = 140,
        height = 20,
        onSelect = function(key, data)
            if VE.EndeavorTracker then
                VE.EndeavorTracker:SelectHouse(key)
            end
        end,
    })
    houseDropdown:SetPoint("LEFT", houseIcon, "RIGHT", 4, 0)
    frame.houseDropdown = houseDropdown

    -- House Level display (right side) - shares space with fetch status
    -- Note: houseLevelText uses inline color codes, so we don't register it with HeaderText
    local houseLevelText = dropdownRow:CreateFontString(nil, "OVERLAY")
    houseLevelText:SetPoint("LEFT", houseDropdown, "RIGHT", 8, 0)
    houseLevelText:SetPoint("RIGHT", -4, 0)
    houseLevelText:SetJustifyH("RIGHT")
    VE.Theme.ApplyFont(houseLevelText, C, "small")
    houseLevelText:SetTextColor(C.text_dim.r, C.text_dim.g, C.text_dim.b)
    houseLevelText:SetText("")
    frame.houseLevelText = houseLevelText

    -- Fetch status text (below dropdown) - shows loading/retry status
    local fetchStatusText = dropdownRow:CreateFontString(nil, "OVERLAY")
    fetchStatusText:SetPoint("TOPLEFT", houseDropdown, "BOTTOMLEFT", 0, -2)
    fetchStatusText:SetJustifyH("LEFT")
    VE.Theme.ApplyFont(fetchStatusText, C, "small")
    fetchStatusText:SetTextColor(C.text_dim.r, C.text_dim.g, C.text_dim.b)
    fetchStatusText._colorType = "text_dim"
    VE.Theme:Register(fetchStatusText, "HeaderText")
    fetchStatusText:Hide()  -- Hidden by default, shown when needed
    frame.fetchStatusText = fetchStatusText

    -- ========================================================================
    -- ROW 2: Coupons (left), Contribution (right)
    -- ========================================================================
    local statsRow = CreateFrame("Frame", nil, headerSection)
    statsRow:SetHeight(16)
    statsRow:SetPoint("TOPLEFT", dropdownRow, "BOTTOMLEFT", -4, -4)
    statsRow:SetPoint("TOPRIGHT", dropdownRow, "BOTTOMRIGHT", -4, -4)

    -- Contribution value (right-most)
    local xpValue = statsRow:CreateFontString(nil, "OVERLAY")
    xpValue:SetPoint("RIGHT", 0, 0)
    VE.Theme.ApplyFont(xpValue, C, "small")
    xpValue:SetTextColor(C.endeavor.r, C.endeavor.g, C.endeavor.b)
    xpValue._colorType = "endeavor"
    VE.Theme:Register(xpValue, "HeaderText")
    frame.xpValue = xpValue

    -- Contribution pip icon
    local contribIcon = statsRow:CreateTexture(nil, "ARTWORK")
    contribIcon:SetSize(14, 14)
    contribIcon:SetPoint("RIGHT", xpValue, "LEFT", -4, 0)
    contribIcon:SetAtlas("housing-dashboard-fillbar-pip-complete")
    frame.contribIcon = contribIcon

    -- House XP text
    local houseXpText = statsRow:CreateFontString(nil, "OVERLAY")
    houseXpText:SetPoint("RIGHT", contribIcon, "LEFT", -12, 0)
    VE.Theme.ApplyFont(houseXpText, C, "small")
    houseXpText:SetTextColor(C.endeavor.r, C.endeavor.g, C.endeavor.b)
    houseXpText._colorType = "endeavor"
    VE.Theme:Register(houseXpText, "HeaderText")
    frame.houseXpText = houseXpText

    -- House XP icon
    local houseXpIcon = statsRow:CreateTexture(nil, "ARTWORK")
    houseXpIcon:SetSize(14, 14)
    houseXpIcon:SetPoint("RIGHT", houseXpText, "LEFT", -4, 0)
    houseXpIcon:SetAtlas("house-reward-increase-arrows")
    houseXpIcon:SetRotation(math.pi / 2) -- 90 degrees counter-clockwise
    frame.houseXpIcon = houseXpIcon

    -- Tooltip hover area for house XP
    local houseXpHover = CreateFrame("Frame", nil, statsRow)
    houseXpHover:SetPoint("LEFT", houseXpIcon, "LEFT", -2, 0)
    houseXpHover:SetPoint("RIGHT", houseXpText, "RIGHT", 2, 0)
    houseXpHover:SetPoint("TOP", houseXpIcon, "TOP", 0, 2)
    houseXpHover:SetPoint("BOTTOM", houseXpIcon, "BOTTOM", 0, -2)
    houseXpHover:EnableMouse(true)
    houseXpHover:SetScript("OnEnter", function(self)
        local colors = VE.Constants:GetThemeColors()
        GameTooltip:SetOwner(self, "ANCHOR_TOP")
        GameTooltip:AddLine("This is a guess!", colors.accent.r, colors.accent.g, colors.accent.b)
        GameTooltip:AddLine(" ")
        GameTooltip:AddLine("House XP Earned", 1, 1, 1)
        GameTooltip:AddLine("Estimated total from completed tasks.", 0.7, 0.7, 0.7, true)
        if frame.houseXpCapped then
            GameTooltip:AddLine(" ")
            GameTooltip:AddLine("You may be capped!", colors.warning.r, colors.warning.g, colors.warning.b)
            GameTooltip:AddLine("XP gains stop after ~1000 per week.", 0.7, 0.7, 0.7, true)
        end
        GameTooltip:AddLine(" ")
        GameTooltip:AddLine("Formula: factor = 0.96 - 0.10 * n", 0.7, 0.7, 0.7)
        GameTooltip:AddLine("n=2: x0.76, n=3: x0.66, n=4: x0.56...", 0.7, 0.7, 0.7)
        GameTooltip:AddLine("Base 50: 50 -> 38 -> 25 -> 14 -> 10", 0.7, 0.7, 0.7)
        GameTooltip:Show()
    end)
    houseXpHover:SetScript("OnLeave", function()
        GameTooltip:Hide()
    end)

    -- Coupons count
    local couponsText = statsRow:CreateFontString(nil, "OVERLAY")
    couponsText:SetPoint("RIGHT", houseXpIcon, "LEFT", -12, 0)
    VE.Theme.ApplyFont(couponsText, C, "small")
    couponsText:SetTextColor(C.warning.r, C.warning.g, C.warning.b)
    couponsText._colorType = "warning"
    VE.Theme:Register(couponsText, "HeaderText")
    frame.couponsText = couponsText

    -- Coupons icon
    local couponsIcon = statsRow:CreateTexture(nil, "ARTWORK")
    couponsIcon:SetSize(14, 14)
    couponsIcon:SetPoint("RIGHT", couponsText, "LEFT", -4, 0)
    frame.couponsIcon = couponsIcon

    -- Position header background to cover entire headerSection
    headerBg:SetPoint("TOPLEFT", headerSection, "TOPLEFT", -padding, 0)
    headerBg:SetPoint("BOTTOMRIGHT", statsRow, "BOTTOMRIGHT", padding, -2)

    -- Update house dropdown when house list changes
    function frame:UpdateHouseDropdown(houseList, selectedIndex)
        if houseList and #houseList > 0 then
            -- Build items for the dropdown
            local items = {}
            for i, houseInfo in ipairs(houseList) do
                table.insert(items, {
                    key = i,
                    label = houseInfo.houseName or ("House " .. i),
                })
            end
            self.houseDropdown:SetItems(items)

            -- Set selected house
            local selectedHouse = houseList[selectedIndex or 1]
            local houseName = selectedHouse and selectedHouse.houseName or "Select House"
            self.houseDropdown:SetSelected(selectedIndex or 1, { label = houseName })
        else
            self.houseDropdown:SetItems({})
            self.houseDropdown:SetSelected(nil, { label = "No houses" })
        end
    end

    -- Fetch status display (shows below dropdown, independent of house level)
    function frame:UpdateFetchStatus(status)
        if not status then
            status = VE.EndeavorTracker and VE.EndeavorTracker.fetchStatus or { state = "pending" }
        end
        local colors = VE.Constants.Colors
        local timestamp = VE.EndeavorTracker and VE.EndeavorTracker.activityLogLastUpdated
        local timeStr = timestamp and date("%H:%M:%S", timestamp) or ""

        -- Cancel any pending fade timer
        if self.fetchStatusFadeTimer then
            self.fetchStatusFadeTimer:Cancel()
            self.fetchStatusFadeTimer = nil
        end

        -- Reset alpha and ensure visible for new messages
        self.fetchStatusText:SetAlpha(1)

        -- Check if we actually have data (tasks or activity log)
        local hasData = false
        local state = VE.Store:GetState()
        if state and state.tasks and #state.tasks > 0 then
            hasData = true
        elseif timestamp then
            hasData = true
        end

        local text = ""

        if status.state == "loaded" and hasData then
            local successColor = string.format("%02x%02x%02x", colors.success.r*255, colors.success.g*255, colors.success.b*255)
            text = "|cFF" .. successColor .. "Data loaded"
            if timeStr ~= "" then
                text = text .. " - " .. timeStr
            end
            text = text .. "|r"

            -- Fade out after 0.5 seconds, then hide
            self.fetchStatusFadeTimer = C_Timer.NewTimer(0.5, function()
                if self.fetchStatusText then
                    UIFrameFadeOut(self.fetchStatusText, 1, 1, 0)
                    C_Timer.After(1, function()
                        self.fetchStatusText:SetText("")
                        self.fetchStatusText:Hide()
                    end)
                end
            end)
        elseif status.state == "fetching" then
            -- Actively fetching - only show if we don't have data yet
            if not hasData then
                text = "|cFF" .. string.format("%02x%02x%02x", colors.warning.r*255, colors.warning.g*255, colors.warning.b*255) .. "Fetching data...|r"
            end
        elseif status.state == "retrying" then
            local remaining = status.nextRetry and (status.nextRetry - time()) or 60
            if remaining < 0 then remaining = 0 end
            text = "|cFF" .. string.format("%02x%02x%02x", colors.warning.r*255, colors.warning.g*255, colors.warning.b*255)
            text = text .. "Retry " .. (status.attempt or 1) .. "/3 in " .. remaining .. "s|r"
        else
            -- Only show waiting message if we don't have data yet
            if not hasData then
                text = "|cFF" .. string.format("%02x%02x%02x", colors.text_dim.r*255, colors.text_dim.g*255, colors.text_dim.b*255) .. "Waiting for data...|r"
            end
        end

        -- Show or hide fetch status text (house level is always visible now)
        if text ~= "" then
            self.fetchStatusText:SetText(text)
            self.fetchStatusText:Show()
        else
            self.fetchStatusText:SetText("")
            self.fetchStatusText:Hide()
        end
    end

    -- Listen for fetch status changes
    VE.EventBus:Register("VE_FETCH_STATUS_CHANGED", function(status)
        if frame.UpdateFetchStatus then
            frame:UpdateFetchStatus(status)
        end
    end)

    -- Listen for activity log updates (refresh status and contribution)
    VE.EventBus:Register("VE_ACTIVITY_LOG_UPDATED", function(payload)
        if frame.UpdateFetchStatus then
            frame:UpdateFetchStatus()
        end
        -- Refresh contribution display (calculated from activity log)
        if frame.UpdateHeader then
            frame:UpdateHeader()
        end
    end)

    -- Listen for house list updates
    VE.EventBus:Register("VE_HOUSE_LIST_UPDATED", function(payload)
        if frame.UpdateHouseDropdown and payload then
            frame:UpdateHouseDropdown(payload.houseList, payload.selectedIndex)
        end
    end)

    -- Ticker to update countdown while retrying
    frame.fetchStatusTicker = C_Timer.NewTicker(1, function()
        if frame:IsShown() and VE.EndeavorTracker then
            local status = VE.EndeavorTracker.fetchStatus
            if status and status.state == "retrying" then
                frame:UpdateFetchStatus(status)
            end
        end
    end)

    -- Request fresh data on show
    frame:HookScript("OnShow", function()
        -- Request housing data via HousingTracker module
        if VE.HousingTracker then
            VE.HousingTracker:RequestHouseInfo()
            VE.HousingTracker:UpdateCoupons()
        end
        -- Request endeavor data for immediate refresh
        if VE.EndeavorTracker then
            VE.EndeavorTracker:FetchEndeavorData()
        end
        -- Update status displays
        frame:UpdateFetchStatus()
        -- Update house dropdown
        if VE.EndeavorTracker then
            frame:UpdateHouseDropdown(VE.EndeavorTracker:GetHouseList(), VE.EndeavorTracker:GetSelectedHouseIndex())
        end
        -- Recreate countdown ticker if needed (cancelled on hide)
        if not frame.fetchStatusTicker then
            frame.fetchStatusTicker = C_Timer.NewTicker(1, function()
                if frame:IsShown() and VE.EndeavorTracker then
                    local status = VE.EndeavorTracker.fetchStatus
                    if status and status.state == "retrying" then
                        frame:UpdateFetchStatus(status)
                    end
                end
            end)
        end
    end)

    -- Cancel ticker and hide tooltip on hide
    frame:HookScript("OnHide", function()
        if frame.fetchStatusTicker then
            frame.fetchStatusTicker:Cancel()
            frame.fetchStatusTicker = nil
        end
        if frame.fetchStatusFadeTimer then
            frame.fetchStatusFadeTimer:Cancel()
            frame.fetchStatusFadeTimer = nil
        end
        if GameTooltip:IsOwned(frame) then
            GameTooltip:Hide()
        end
    end)

    -- Update header function
    function frame:UpdateHeader()
        local state = VE.Store:GetState()

        self.seasonName:SetText(state.endeavor.seasonName or "Housing Endeavors")

        if state.endeavor.daysRemaining and state.endeavor.daysRemaining > 0 then
            self.daysRemaining:SetText(state.endeavor.daysRemaining .. " Days Remaining")
        else
            self.daysRemaining:SetText("")
        end

        self.progressBar:SetProgress(
            state.endeavor.currentProgress or 0,
            state.endeavor.maxProgress or 100
        )
        self.progressBar:SetMilestones(
            state.endeavor.milestones,
            state.endeavor.maxProgress or 100
        )

        -- Update contribution display (from activity log for current player)
        local playerContribution = 0
        local activityData = VE.EndeavorTracker:GetActivityLogData()
        local debug = VE.Store:GetState().config.debug
        if activityData and activityData.taskActivity then
            local currentPlayer = UnitName("player")
            local entryCount = 0
            for _, entry in ipairs(activityData.taskActivity) do
                if entry.playerName == currentPlayer then
                    playerContribution = playerContribution + (entry.amount or 0)
                    entryCount = entryCount + 1
                    if debug then
                        print(string.format("|cFF2aa198[VE Contrib]|r %s: +%.1f (%s)",
                            entry.taskName or "?", entry.amount or 0, entry.playerName or "?"))
                    end
                end
            end
            if debug and entryCount > 0 then
                print(string.format("|cFF2aa198[VE Contrib]|r Total: %.1f from %d entries", playerContribution, entryCount))
            end
        end
        -- Contribution = endeavor progress (from activity log)
        self.xpValue:SetText(string.format("%.1f", playerContribution))

        -- House XP = reward from completed tasks (with DR calculation)
        local houseXpEarned = 0
        if state.tasks and VE.EndeavorTracker then
            for _, task in ipairs(state.tasks) do
                houseXpEarned = houseXpEarned + VE.EndeavorTracker:GetTaskTotalHouseXPEarned(task)
            end
        end
        self.houseXpText:SetText(tostring(houseXpEarned))
        -- Grey out if potentially capped (>1000 XP)
        local colors = VE.Constants:GetThemeColors()
        if houseXpEarned > 1000 then
            self.houseXpText:SetTextColor(colors.text_dim.r, colors.text_dim.g, colors.text_dim.b)
            self.houseXpText._colorType = "text_dim"  -- Update for theme engine
            self.houseXpCapped = true
        else
            self.houseXpText:SetTextColor(colors.endeavor.r, colors.endeavor.g, colors.endeavor.b)
            self.houseXpText._colorType = "endeavor"  -- Update for theme engine
            self.houseXpCapped = false
        end
    end

    -- ========================================================================
    -- CONTENT CONTAINER (collapsible)
    -- ========================================================================

    local content = CreateFrame("Frame", nil, frame)
    content:SetPoint("TOPLEFT", 0, -UI.headerContentOffset)
    content:SetPoint("BOTTOMRIGHT", 0, 0)
    frame.content = content

    -- ========================================================================
    -- TAB PANELS
    -- ========================================================================

    -- Endeavors tab (main view)
    local endeavorsTab = VE.UI.Tabs:CreateEndeavors(content)
    endeavorsTab:SetAllPoints()
    frame.endeavorsTab = endeavorsTab

    -- Leaderboard tab
    local leaderboardTab = VE.UI.Tabs:CreateLeaderboard(content)
    leaderboardTab:SetAllPoints()
    leaderboardTab:Hide()
    frame.leaderboardTab = leaderboardTab

    -- Activity tab
    local activityTab = VE.UI.Tabs:CreateActivity(content)
    activityTab:SetAllPoints()
    activityTab:Hide()
    frame.activityTab = activityTab

    -- Config tab (settings)
    local configTab = VE.UI.Tabs:CreateConfig(content)
    configTab:SetAllPoints()
    configTab:Hide()
    frame.configTab = configTab

    -- ========================================================================
    -- TAB SWITCHING
    -- ========================================================================

    local function ShowTab(tabName)
        -- Hide all tabs
        endeavorsTab:Hide()
        leaderboardTab:Hide()
        activityTab:Hide()
        configTab:Hide()

        -- Deactivate all buttons
        endeavorsTabBtn:SetActive(false)
        leaderboardTabBtn:SetActive(false)
        activityTabBtn:SetActive(false)
        configTabBtn:SetActive(false)

        -- Show selected tab
        if tabName == "endeavors" then
            endeavorsTab:Show()
            endeavorsTabBtn:SetActive(true)
            VE:RefreshUI()
        elseif tabName == "leaderboard" then
            leaderboardTab:Show()
            leaderboardTabBtn:SetActive(true)
        elseif tabName == "activity" then
            activityTab:Show()
            activityTabBtn:SetActive(true)
        elseif tabName == "config" then
            configTab:Show()
            configTabBtn:SetActive(true)
        end
    end

    endeavorsTabBtn:SetScript("OnClick", function()
        ShowTab("endeavors")
    end)

    leaderboardTabBtn:SetScript("OnClick", function()
        ShowTab("leaderboard")
    end)

    activityTabBtn:SetScript("OnClick", function()
        ShowTab("activity")
    end)

    configTabBtn:SetScript("OnClick", function()
        ShowTab("config")
    end)

    -- Default to endeavors tab
    ShowTab("endeavors")

    -- Initial updates
    frame:UpdateHousingDisplay()
    frame:UpdateHeader()

    frame.ShowTab = ShowTab

    self.MainFrame = frame

    -- Listen for state changes to refresh UI
    VE.EventBus:Register("VE_STATE_CHANGED", function(payload)
        if not frame:IsShown() then return end

        -- Always update housing display on any state change
        if payload.action == "SET_HOUSE_LEVEL" or payload.action == "SET_COUPONS" then
            frame:UpdateHousingDisplay()
        end

        -- Update header (progress bar) when endeavor info changes
        if payload.action == "SET_ENDEAVOR_INFO" or payload.action == "SET_TASKS" then
            frame:UpdateHeader()
        end

        -- Refresh endeavors tab if visible
        if endeavorsTab:IsShown() then
            VE:RefreshUI()
        end
    end)

    -- Listen for theme updates
    -- Note: Most theming is handled by Theme Engine via registered widgets
    -- We only need to update houseLevelText here because it uses inline color codes
    VE.EventBus:Register("VE_THEME_UPDATE", function()
        local colors = VE.Constants:GetThemeColors()
        VE.Theme.ApplyFont(frame.houseLevelText, colors, "small")
        frame:UpdateHousingDisplay()
    end)

    -- Listen for UI scale changes
    VE.EventBus:Register("VE_UI_SCALE_UPDATE", function()
        local scale = VE.Store:GetState().config.uiScale or 1.0
        frame:SetScale(scale)
    end)

    return frame
end
