local addonName, privateDB = ...
local HDG = _G.HousingDecorGuide

-- Module namespace
HDG_UI = {}

-- Local references
local CONFIG = privateDB.CONFIG
local L = HDG_L or {}  -- Localization

-- ============================================================================
-- THEME HELPERS (delegating to ThemeEngine canonical helpers)
-- ============================================================================

local function GetScheme() return HDG.Theme.GetCurrentScheme() end
local function RegisterWidget(w, t) HDG.Theme.RegisterWidget(w, t) end
local ApplyFont = function(fs, s, ft) HDG.Theme.ApplyFont(fs, s, ft) end

-- Color code helpers (dynamic theme colors)
local function C_Text() return HDG.Theme.C_Text() end
local function C_Header() return HDG.Theme.C_Header() end
local function C_Dim() return HDG.Theme.C_Dim() end
local function C_Accent() return HDG.Theme.C_Accent() end
local function C_Success() return HDG.Theme.C_Success() end
local function C_Warning() return HDG.Theme.C_Warning() end
local function C_Error() return HDG.Theme.C_Error() end

-- ============================================================================
-- STORE HELPERS
-- ============================================================================

local function GetStore()
    local hdg = _G.HousingDecorGuide
    return hdg and hdg.Store
end

local function GetState()
    local store = GetStore()
    return store and store:GetState()
end

local function Dispatch(action, payload)
    local store = GetStore()
    if store then
        store:Dispatch(action, payload)
    end
end

local function GetConfig(key)
    local state = GetState()
    return state and state.config and state.config[key]
end

local function GetUIState(key)
    local state = GetState()
    return state and state.ui and state.ui[key]
end

local function GetShoppingList()
    local state = GetState()
    return state and state.shoppingList or {}
end

-- HDG_Data is global, so we can access it directly or via _G.HDG_Data
-- Check if HDG_Data is initialized, if not, use _G.HDG_Data
local HDG_Data = _G.HDG_Data
-- Note: privateDB.HDG_Data might be nil if initialized later, so best to rely on _G

-- UI State
local mainFrame
local activeTab = "recipes"

-- Orc quotes for footer (changes on PLAYER_ENTERING_WORLD)
local ORC_QUOTES = {
    "Zug zug.",
    "Lok'tar ogar!",
    "Me smash!",
    "Work is da poop!",
    "Blood and Thunder!",
    "Dabu.",
    "Time to kill?",
    "For the Horde!",
    "Me busy!",
    "Axe hungry.",
    "Crush them all!",
    "Why you poke me?",
    "Strength and Honor.",
    "Me not that kind of orc.",
    "You weak. Me strong.",
    "More wood? Ugh.",
    "Me hit it now?",
    "Victory or death!",
    "Small talk is for elves.",
    "Something need doing?",
}
local currentQuote = ORC_QUOTES[math.random(#ORC_QUOTES)]

-- Use centralized Data() accessor from UIHelpers
local function Data()
    return HDG_UIHelpers.Data()
end

-- ============================================================================
-- HELPER FUNCTIONS
-- ============================================================================

-- Use centralized ClearScrollContent from UIHelpers
local function ClearScrollContent(scrollContent)
    HDG_UIHelpers.ClearScrollContent(scrollContent)
end

-- Use centralized GetProgressBarColor from UIHelpers
local function GetProgressBarColor(percentage)
    return HDG_UIHelpers.GetProgressBarColor(percentage)
end

local function CreateProgressBar(parent, have, needed, xPos, yPos, showText)
    if not CONFIG.PROGRESS_BAR.SHOW_BARS then return nil end

    local bar = CreateFrame("StatusBar", nil, parent, "BackdropTemplate")
    bar:SetSize(CONFIG.PROGRESS_BAR.WIDTH, CONFIG.PROGRESS_BAR.HEIGHT)
    bar:SetPoint("RIGHT", xPos or -60, yPos or 0)
    bar:SetStatusBarTexture(CONFIG.TEXTURES.STATUSBAR)
    bar:SetMinMaxValues(0, needed)
    bar:SetValue(math.min(have, needed))

    local percentage = needed > 0 and (have / needed * 100) or 0
    bar:SetStatusBarColor(GetProgressBarColor(percentage))

    local scheme = GetScheme()
    local bg = bar:CreateTexture(nil, "BACKGROUND")
    bg:SetAllPoints(bar)
    bg:SetTexture(CONFIG.TEXTURES.STATUSBAR)
    bg:SetVertexColor(scheme.bg.r, scheme.bg.g, scheme.bg.b, 0.7)

    if showText then
        local text = bar:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        text:SetPoint("CENTER", 0, 0)
        text:SetJustifyH("CENTER")
        ApplyFont(text, scheme, "small", 10)
        if have >= needed then
            local extra = have - needed
            text:SetText(extra > 0 and string.format(C_Text() .. "%d/%d+%d|r", needed, needed, extra) or
                string.format(C_Text() .. "%d/%d|r", needed, needed))
        else
            text:SetText(string.format(C_Text() .. "%d/%d|r", have, needed))
        end
        bar.text = text
    end

    return bar
end

-- Helper: Count known recipes
function HDG_UI.CountKnownRecipes(profData)
    if not profData or not profData.items then return 0 end

    local knownCount = 0
    local dataModule = Data()
    local knowsBySpellID = dataModule.PlayerKnowsRecipeBySpellID
    local knowsByName = dataModule.PlayerKnowsRecipe

    for _, recipe in ipairs(profData.items) do
        local isKnown = false
        if recipe.spell and recipe.spell > 0 then
            isKnown = knowsBySpellID and knowsBySpellID(recipe.spell)
        elseif knowsByName then
            isKnown = knowsByName(recipe.name)
        end

        if isKnown then
            knownCount = knownCount + 1
        end
    end
    return knownCount
end

-- CreateLumberRow is now provided by HDG_UIHelpers.CreateLumberRow

-- ============================================================================
-- UI CREATION
-- ============================================================================

function HDG_UI.CreateUI()
    if mainFrame then return end

    local scheme = GetScheme()

    mainFrame = CreateFrame("Frame", "HDG_MainFrame", UIParent, "BackdropTemplate")

    -- Default size (scaling now handled via UI Scale slider in settings)
    local defaultWidth = CONFIG.MAIN_FRAME_WIDTH
    local defaultHeight = CONFIG.MAIN_FRAME_HEIGHT

    mainFrame:SetSize(defaultWidth, defaultHeight)

    -- Restore saved layout (new system) or position (legacy) or default to center
    local state = HDG.Store and HDG.Store:GetState()
    local layout = state and state.layout and state.layout.MainFrame
    local savedPos = GetUIState("framePosition")

    if layout and layout.point then
        -- New layout system - restore position only (size controlled via UI Scale)
        mainFrame:SetPoint(layout.point, UIParent, layout.relPoint or layout.point, layout.x or 0, layout.y or 0)
    elseif savedPos and savedPos[1] and savedPos[3] and savedPos[4] then
        -- Legacy position system
        mainFrame:SetPoint(savedPos[1], UIParent, savedPos[2] or savedPos[1], savedPos[3], savedPos[4])
    else
        mainFrame:SetPoint("CENTER")
    end

    mainFrame:SetBackdrop({
        bgFile = CONFIG.TEXTURES.WHITE_BG,
        edgeFile = CONFIG.TEXTURES.WHITE_BG,  -- Solid 2px border (consistent with panels)
        tile = false,
        edgeSize = 1,
        insets = { left = 0, right = 0, top = 0, bottom = 0 }
    })
    mainFrame:SetBackdropColor(scheme.bg.r, scheme.bg.g, scheme.bg.b, scheme.bg.a)
    mainFrame:SetBackdropBorderColor(scheme.border.r, scheme.border.g, scheme.border.b, scheme.border.a)

    -- Atlas wood frame border (Housing Theme) - overlay frame for decorative border
    local borderFrame = CreateFrame("Frame", nil, mainFrame)
    borderFrame:SetAllPoints()
    borderFrame:SetFrameLevel(mainFrame:GetFrameLevel() + 10)  -- Render on top
    local borderTex = borderFrame:CreateTexture(nil, "OVERLAY")
    borderTex:SetAllPoints()
    borderTex:SetAtlas("housing-wood-frame")
    borderTex:SetAlpha(1)
    borderFrame.tex = borderTex
    mainFrame.borderFrame = borderFrame
    -- Initial visibility based on theme
    if scheme.atlas and scheme.atlas.windowBorder then
        borderFrame:Show()
    else
        borderFrame:Hide()
    end

    -- Register with Theme Engine (MainWindow gets atlas bg + border for HousingTheme)
    RegisterWidget(mainFrame, "MainWindow")

    -- Apply saved UI scale
    local savedScale = state and state.config and state.config.scale or 1.0
    mainFrame:SetScale(savedScale)

    mainFrame:SetFrameStrata("MEDIUM")
    mainFrame:SetToplevel(true)  -- Raise to top when clicked
    mainFrame:SetMovable(true)
    mainFrame:EnableMouse(true)
    mainFrame:RegisterForDrag("LeftButton")
    mainFrame:SetScript("OnDragStart", mainFrame.StartMoving)
    mainFrame:SetScript("OnDragStop", function(self)
        self:StopMovingOrSizing()
        local point, _, relativePoint, xOfs, yOfs = self:GetPoint()
        -- Legacy position system
        Dispatch("SET_FRAME_POSITION", { position = { point, relativePoint, xOfs, yOfs } })
        -- New layout system (includes size)
        if HDG.Store then
            HDG.Store:Dispatch("UPDATE_LAYOUT", {
                frame = "MainFrame",
                width = self:GetWidth(),
                height = self:GetHeight(),
                point = point,
                relPoint = relativePoint,
                x = xOfs,
                y = yOfs,
            })
        end
    end)
    mainFrame:SetScript("OnShow", function()
        -- Update pinned lumber widget's expand button when main window opens
        if HDG_LumberTracker and HDG_LumberTracker.IsPinnedVisible and HDG_LumberTracker.IsPinnedVisible() then
            local pinnedFrame = HDG_LumberTracker.GetPinnedFrame()
            if pinnedFrame and pinnedFrame.expandBtn and pinnedFrame.expandBtn.UpdateState then
                pinnedFrame.expandBtn.UpdateState()
            end
        end
    end)
    mainFrame:SetScript("OnHide", function()
        -- Update pinned lumber widget's expand button when main window closes
        if HDG_LumberTracker and HDG_LumberTracker.IsPinnedVisible and HDG_LumberTracker.IsPinnedVisible() then
            local pinnedFrame = HDG_LumberTracker.GetPinnedFrame()
            if pinnedFrame and pinnedFrame.expandBtn and pinnedFrame.expandBtn.UpdateState then
                pinnedFrame.expandBtn.UpdateState()
            end
        end
    end)
    mainFrame:Hide()
    table.insert(UISpecialFrames, "HDG_MainFrame")

    -- Initialize Trainers Module (needs mainFrame)
    if _G.HDG_Trainers and _G.HDG_Trainers.Init then
        _G.HDG_Trainers:Init(CONFIG, mainFrame, Data().PlayerHasProfession)
    end


    -- Title area background (HousingTheme atlas) - rotated 90 degrees, stretched horizontally
    local titleBgScheme = GetScheme()
    if titleBgScheme and titleBgScheme.atlas and titleBgScheme.atlas.titleBg then
        local titleBg = mainFrame:CreateTexture(nil, "BACKGROUND", nil, -7)
        titleBg:SetAtlas(titleBgScheme.atlas.titleBg)
        -- Rotate 90 degrees clockwise using 8-param SetTexCoord (UL, LL, UR, LR)
        titleBg:SetTexCoord(0, 1, 1, 1, 0, 0, 1, 0)
        -- After rotation, atlas width becomes our height
        local atlasInfo = C_Texture.GetAtlasInfo(titleBgScheme.atlas.titleBg)
        local nativeHeight = atlasInfo and atlasInfo.width or CONFIG.BANNER_HEIGHT
        titleBg:SetPoint("TOPLEFT", 0, 0)
        titleBg:SetPoint("TOPRIGHT", 0, 0)
        titleBg:SetHeight(nativeHeight)
        mainFrame.titleBgTexture = titleBg
    end

    -- Title textures - Vamoose's (left) + Housing Decor Guide (right)
    -- Images extend beyond frame edges for dramatic effect
    local title1Height = 45  -- Vamoose's
    local title1Width = 400 * (title1Height / 89)  -- Maintain aspect ratio (400x89 source)
    local title2Height = 40.5  -- Housing Decor Guide (90% of original 45)
    local title2Width = 157 * (title2Height / 42)  -- Maintain aspect ratio (157x42 source)

    -- Create a title overlay frame that sits above borderFrame for all themes
    local titleOverlay = CreateFrame("Frame", nil, mainFrame)
    titleOverlay:SetAllPoints(mainFrame)
    titleOverlay:SetFrameLevel(mainFrame:GetFrameLevel() + 15)  -- Above borderFrame (which is +10)
    mainFrame.titleOverlay = titleOverlay

    mainFrame.title1Texture = titleOverlay:CreateTexture(nil, "OVERLAY", nil, 7)
    mainFrame.title1Texture:SetTexture(CONFIG.ADDON_TEXTURES.TITLE1)
    mainFrame.title1Texture:SetSize(title1Width, title1Height)
    mainFrame.title1Texture:SetPoint("TOPLEFT", mainFrame, "TOPLEFT", -10, 12)  -- Extend left of frame
    mainFrame.title1Texture:SetVertexColor(0.8, 0.8, 0.8)  -- Dim 20%

    mainFrame.title2Texture = titleOverlay:CreateTexture(nil, "OVERLAY", nil, 7)
    mainFrame.title2Texture:SetTexture(CONFIG.ADDON_TEXTURES.TITLE2)
    mainFrame.title2Texture:SetSize(title2Width, title2Height)
    mainFrame.title2Texture:SetPoint("LEFT", mainFrame.title1Texture, "RIGHT", -2, -8)
    mainFrame.title2Texture:SetVertexColor(0.8, 0.8, 0.8)  -- Dim 20%

    -- Version text (bottom left of window)
    local titleScheme = GetScheme()
    mainFrame.titleText = mainFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    mainFrame.titleText:SetPoint("BOTTOMLEFT", 10, 6)
    ApplyFont(mainFrame.titleText, titleScheme, "small")
    mainFrame.titleText:SetText(string.format(C_Dim() .. "v%s|r", privateDB.ADDON_VERSION))

    -- Progress bar removed - totals now shown in profession tabs TOTAL row

    -- Close button (housing door atlas)
    local closeBtn = CreateFrame("Button", nil, mainFrame)
    closeBtn:SetSize(22, 22)
    closeBtn:SetPoint("TOPRIGHT", -6, -8)
    local closeIcon = closeBtn:CreateTexture(nil, "ARTWORK")
    closeIcon:SetAllPoints()
    closeIcon:SetAtlas("housing-floor-door-inactive")
    closeIcon:SetVertexColor(0.7, 0.7, 0.7, 1)  -- Dimmed when not hovered
    closeBtn.icon = closeIcon
    closeBtn:SetScript("OnClick", function() mainFrame:Hide() end)
    closeBtn:SetScript("OnEnter", function(self)
        self.icon:SetAtlas("housing-floor-door")
        self.icon:SetVertexColor(1, 1, 1, 1)
        GameTooltip:SetOwner(self, "ANCHOR_BOTTOM")
        GameTooltip:AddLine("Close", 1, 1, 1)
        GameTooltip:Show()
    end)
    closeBtn:SetScript("OnLeave", function(self)
        self.icon:SetAtlas("housing-floor-door-inactive")
        self.icon:SetVertexColor(0.7, 0.7, 0.7, 1)
        GameTooltip:Hide()
    end)

    -- Refresh button (sync atlas)
    local refreshBtn = CreateFrame("Button", nil, mainFrame)
    refreshBtn:SetSize(24, 24)
    refreshBtn:SetPoint("TOPRIGHT", closeBtn, "TOPLEFT", -4, 0)
    local refreshIcon = refreshBtn:CreateTexture(nil, "ARTWORK")
    refreshIcon:SetSize(22, 22)
    refreshIcon:SetPoint("CENTER")
    refreshIcon:SetAtlas("housefinder_neighborhood-party-sync-icon")
    refreshIcon:SetVertexColor(0.7, 0.7, 0.7, 1)  -- Dimmed when not hovered
    refreshBtn.icon = refreshIcon
    refreshBtn:SetScript("OnClick", function()
        Data().ClearCaches()
        HDG_Data.CollectCharacterProfessions()  -- Re-scan profession skill levels

        -- Refresh all tabs
        if privateDB.HDG_RecipesTab then privateDB.HDG_RecipesTab:Refresh() end
        if privateDB.HDG_GoblinTab and privateDB.HDG_GoblinTab.Refresh then privateDB.HDG_GoblinTab.Refresh() end
        if HDG_DecorPreview and HDG_DecorPreview.Refresh then HDG_DecorPreview:Refresh() end
        if _G.HDG_Trainers and _G.HDG_Trainers.Refresh then _G.HDG_Trainers:Refresh() end
        if privateDB.HDG_AltsTab and privateDB.HDG_AltsTab.Refresh then privateDB.HDG_AltsTab.Refresh() end
        if privateDB.HDG_DataTab and privateDB.HDG_DataTab.RefreshFarmingDisplay then privateDB.HDG_DataTab.RefreshFarmingDisplay() end

        HDG_UI.RefreshMaterials()
        HDG_UI.RefreshLumberTracking()

        print(C_Success() .. "Housing Decor Guide:|r Refreshed all tabs and cleared caches")
    end)
    refreshBtn:SetScript("OnEnter", function(self)
        self.icon:SetVertexColor(1, 1, 1, 1)
        GameTooltip:SetOwner(self, "ANCHOR_BOTTOM")
        GameTooltip:AddLine("Refresh", 1, 1, 1)
        GameTooltip:AddLine("Clears caches and refreshes all tabs", 0.7, 0.7, 0.7, true)
        GameTooltip:Show()
    end)
    refreshBtn:SetScript("OnLeave", function(self)
        self.icon:SetVertexColor(0.7, 0.7, 0.7, 1)
        GameTooltip:Hide()
    end)
    mainFrame.refreshBtn = refreshBtn

    -- Help button (question mark atlas)
    local helpBtn = CreateFrame("Button", nil, mainFrame)
    helpBtn:SetSize(22, 22)
    helpBtn:SetPoint("TOPRIGHT", refreshBtn, "TOPLEFT", -4, 0)
    local helpIcon = helpBtn:CreateTexture(nil, "ARTWORK")
    helpIcon:SetAllPoints()
    helpIcon:SetAtlas("QuestTurnin")
    helpIcon:SetVertexColor(0.7, 0.7, 0.7, 1)  -- Dimmed when not hovered
    helpBtn.icon = helpIcon
    helpBtn:SetScript("OnClick", function()
        -- Switch to Config tab
        Dispatch("SET_ACTIVE_TAB", { tab = "config" })
        HDG_UI.UpdateTabs()
    end)
    helpBtn:SetScript("OnEnter", function(self)
        self.icon:SetVertexColor(1, 1, 1, 1)
        GameTooltip:SetOwner(self, "ANCHOR_BOTTOM")
        GameTooltip:AddLine("Help", 1, 1, 1)
        GameTooltip:AddLine("Opens the How to Use guide", 0.7, 0.7, 0.7, true)
        GameTooltip:Show()
    end)
    helpBtn:SetScript("OnLeave", function(self)
        self.icon:SetVertexColor(0.7, 0.7, 0.7, 1)
        GameTooltip:Hide()
    end)
    mainFrame.helpBtn = helpBtn

    -- Theme switcher button (alterations atlas)
    local themeBtn = CreateFrame("Button", nil, mainFrame)
    themeBtn:SetSize(22, 22)
    themeBtn:SetPoint("TOPRIGHT", helpBtn, "TOPLEFT", -4, 0)
    themeBtn:RegisterForClicks("LeftButtonUp", "RightButtonUp")

    local themeIcon = themeBtn:CreateTexture(nil, "ARTWORK")
    themeIcon:SetAllPoints()
    themeIcon:SetAtlas("decor-ability-alterations-active")
    themeIcon:SetVertexColor(0.7, 0.7, 0.7, 1)  -- Dimmed when not hovered
    themeBtn.icon = themeIcon

    themeBtn:SetScript("OnMouseDown", function() themeIcon:SetAtlas("decor-ability-alterations-pressed") end)
    themeBtn:SetScript("OnMouseUp", function() themeIcon:SetAtlas("decor-ability-alterations-active") end)

    -- Helper to show/update theme tooltip
    local function ShowThemeTooltip(btn)
        local HDG = _G.HousingDecorGuide
        local currentTheme = GetConfig("theme") or "SolarizedDark"
        local currentName = (HDG and HDG.Colors and HDG.Colors.ThemeNames[currentTheme]) or currentTheme
        local nextTheme = HDG.Colors:GetNextTheme(currentTheme)
        local prevTheme = HDG.Colors:GetPreviousTheme(currentTheme)
        local nextName = HDG.Colors.ThemeNames[nextTheme] or nextTheme
        local prevName = HDG.Colors.ThemeNames[prevTheme] or prevTheme

        GameTooltip:ClearLines()
        GameTooltip:SetOwner(btn, "ANCHOR_BOTTOM")
        GameTooltip:AddLine("Change Theme", 1, 1, 1)
        GameTooltip:AddLine("Current: " .. currentName, 0.7, 0.7, 0.7, true)
        GameTooltip:AddLine(" ")
        GameTooltip:AddLine("Left-click: " .. nextName, 0.5, 0.8, 0.5, true)
        GameTooltip:AddLine("Right-click: " .. prevName, 0.8, 0.5, 0.5, true)
        GameTooltip:Show()
    end

    themeBtn:SetScript("OnClick", function(self, button)
        local HDG = _G.HousingDecorGuide
        if not HDG or not HDG.Colors then return end

        local currentTheme = GetConfig("theme") or "SolarizedDark"
        local newTheme

        if button == "RightButton" then
            newTheme = HDG.Colors:GetPreviousTheme(currentTheme)
        else
            newTheme = HDG.Colors:GetNextTheme(currentTheme)
        end

        -- Dispatch to Store
        Dispatch("SET_THEME", { theme = newTheme })

        -- Trigger theme update event for ThemeEngine
        if HDG.EventBus then
            HDG.EventBus:Trigger("HDG_THEME_UPDATE", { themeName = newTheme })
        end

        -- Print notification
        local themeName = HDG.Colors.ThemeNames[newTheme] or newTheme
        print(C_Accent() .. "[HDG]|r Theme: " .. C_Warning() .. themeName .. "|r")

        -- Update tooltip if still hovering
        if GameTooltip:IsShown() and GameTooltip:GetOwner() == self then
            ShowThemeTooltip(self)
        end
    end)

    themeBtn:SetScript("OnEnter", function(self)
        self.icon:SetVertexColor(1, 1, 1, 1)
        ShowThemeTooltip(self)
    end)

    themeBtn:SetScript("OnLeave", function(self)
        self.icon:SetVertexColor(0.7, 0.7, 0.7, 1)
        GameTooltip:Hide()
    end)

    mainFrame.themeBtn = themeBtn

    -- Dye Studio button (opens Vamoose's Dye Studio)
    local dyeBtn = CreateFrame("Button", nil, mainFrame)
    dyeBtn:SetSize(22, 22)
    dyeBtn:SetPoint("TOPRIGHT", themeBtn, "TOPLEFT", -4, 0)

    -- 2x3 rainbow swatch grid as button icon
    local pad, gap = 2, 1
    local cellW = math.floor((22 - pad * 2 - gap * 2) / 3)
    local cellH = math.floor((22 - pad * 2 - gap) / 2)
    local swatchColors = {
        {0.86, 0.08, 0.24}, {1.00, 0.84, 0.00}, {0.20, 0.80, 0.20},
        {0.25, 0.41, 0.88}, {0.60, 0.20, 0.80}, {1.00, 0.41, 0.71},
    }
    dyeBtn.swatches = {}
    for i, c in ipairs(swatchColors) do
        local col = (i - 1) % 3
        local row = math.floor((i - 1) / 3)
        local tex = dyeBtn:CreateTexture(nil, "ARTWORK")
        tex:SetSize(cellW, cellH)
        tex:SetPoint("TOPLEFT", pad + col * (cellW + gap), -(pad + row * (cellH + gap)))
        tex:SetColorTexture(c[1] * 0.7, c[2] * 0.7, c[3] * 0.7)
        tex.baseColor = c
        dyeBtn.swatches[i] = tex
    end
    dyeBtn.icon = dyeBtn.swatches[1] -- for compat

    dyeBtn:SetScript("OnClick", function()
        if HDG_DyePanel then HDG_DyePanel.Toggle() end
    end)
    dyeBtn:SetScript("OnEnter", function(self)
        for _, tex in ipairs(self.swatches) do
            local c = tex.baseColor
            tex:SetColorTexture(c[1], c[2], c[3])
        end
        GameTooltip:SetOwner(self, "ANCHOR_BOTTOM")
        GameTooltip:AddLine("|cFF00CED1Dye Studio|r")
        local b = "\226\150\136\226\150\136" -- ██ color swatch blocks
        GameTooltip:AddLine(
            "|cFFDC143C" .. b .. "|cFFFF8C00" .. b .. "|cFFFFD700" .. b ..
            "|cFF32CD32" .. b .. "|cFF00CED1" .. b .. "|cFF4169E1" .. b ..
            "|cFF9932CC" .. b .. "|cFFFF69B4" .. b .. "|cFF8B6914" .. b ..
            "|cFF808080" .. b .. "|cFF333333" .. b .. "|cFFE8E8E8" .. b .. "|r"
        )
        GameTooltip:AddLine("Browse & preview 62 dye colors", 0.7, 0.7, 0.7, true)
        GameTooltip:AddLine("Create & share custom palettes", 0.7, 0.7, 0.7, true)
        GameTooltip:Show()
    end)
    dyeBtn:SetScript("OnLeave", function(self)
        for _, tex in ipairs(self.swatches) do
            local c = tex.baseColor
            tex:SetColorTexture(c[1] * 0.7, c[2] * 0.7, c[3] * 0.7)
        end
        GameTooltip:Hide()
    end)
    mainFrame.dyeBtn = dyeBtn

    -- Title row separator line
    local titleSeparator = mainFrame:CreateTexture(nil, "ARTWORK")
    titleSeparator:SetHeight(1)
    titleSeparator:SetPoint("TOPLEFT", 8, -(CONFIG.BANNER_HEIGHT + 2))
    titleSeparator:SetPoint("TOPRIGHT", -8, -(CONFIG.BANNER_HEIGHT + 2))
    local sepScheme = GetScheme()
    if sepScheme then
        titleSeparator:SetColorTexture(sepScheme.border.r, sepScheme.border.g, sepScheme.border.b, 0.6)
    else
        titleSeparator:SetColorTexture(0.4, 0.4, 0.4, 0.6)
    end
    RegisterWidget(titleSeparator, "Separator")

    -- Tab System
    local tabContainer = CreateFrame("Frame", nil, mainFrame)
    tabContainer:SetPoint("TOPLEFT", 15, -(CONFIG.BANNER_HEIGHT + 5))
    tabContainer:SetPoint("TOPRIGHT", -15, -(CONFIG.BANNER_HEIGHT + 5))
    tabContainer:SetHeight(CONFIG.TAB_HEIGHT)
    mainFrame.tabContainer = tabContainer

    -- Wood sign background for tab bar (HousingTheme only)
    -- Full window width, positioned at tab bar height
    local tabBgTexture = mainFrame:CreateTexture(nil, "ARTWORK", nil, -7)
    tabBgTexture:SetPoint("TOPLEFT", 0, -(CONFIG.BANNER_HEIGHT + 5))
    tabBgTexture:SetPoint("TOPRIGHT", 0, -(CONFIG.BANNER_HEIGHT + 5))
    tabBgTexture:SetHeight(CONFIG.TAB_HEIGHT)
    tabBgTexture:Hide()
    mainFrame.tabBgTexture = tabBgTexture

    -- Apply atlas if HousingTheme
    local tabBgScheme = GetScheme()
    if tabBgScheme and tabBgScheme.atlas and tabBgScheme.atlas.titleWoodSign then
        tabBgTexture:SetAtlas(tabBgScheme.atlas.titleWoodSign)
        tabBgTexture:Show()
    end

    local tabData = {
        { name = L["TAB_RECIPES"] or "Recipes",   key = "recipes",    side = "left", fullButton = CONFIG.ADDON_TEXTURES.TAB_RECIPES },
        { name = "Acquire",                        key = "acquisition", side = "left", fullButton = CONFIG.ADDON_TEXTURES.TAB_ACQUIRE },
        { name = L["TAB_PREVIEW"] or "Preview",   key = "preview",    side = "left", fullButton = CONFIG.ADDON_TEXTURES.TAB_PREVIEW },
        { name = L["TAB_GOBLIN"] or "Goblin",     key = "goblin",     side = "left", fullButton = CONFIG.ADDON_TEXTURES.TAB_GOBLIN },
        { name = L["TAB_TRAINERS"] or "Trainers", key = "trainers",   side = "left", fullButton = CONFIG.ADDON_TEXTURES.TAB_TRAINERS },
        { name = L["TAB_ALTS"] or "Alts",         key = "characters", side = "left", fullButton = CONFIG.ADDON_TEXTURES.TAB_ALTS },
        { name = L["TAB_DATA"] or "Data",         key = "data",       side = "right", fullButton = CONFIG.ADDON_TEXTURES.TAB_DATA },
        { name = L["TAB_CONFIG"] or "Config",     key = "config",     side = "right", fullButton = CONFIG.ADDON_TEXTURES.TAB_CONFIG }
    }

    local tabs = {}
    local leftOffset = 0
    local rightOffset = 2
    for i, tabInfo in ipairs(tabData) do
        local tabBar

        if tabInfo.fullButton then
            -- Full button mode: plain Frame, wood sign shows through transparent areas
            tabBar = CreateFrame("Frame", nil, tabContainer)
            tabBar:SetSize(95, CONFIG.TAB_HEIGHT - 2)

            if tabInfo.side == "right" then
                tabBar:SetPoint("RIGHT", -rightOffset, 0)
                rightOffset = rightOffset + 97
            else
                tabBar:SetPoint("LEFT", leftOffset, 0)
                leftOffset = leftOffset + 97
            end

            tabBar.key = tabInfo.key
            tabBar.isFullButton = true

            local fullButtonTex = tabBar:CreateTexture(nil, "ARTWORK")
            fullButtonTex:SetAllPoints()
            fullButtonTex:SetTexture(tabInfo.fullButton)
            tabBar.fullButtonTex = fullButtonTex
            tabBar.icon = nil
            tabBar.text = nil
        else
            -- Normal mode: StatusBar with icon + text
            tabBar = CreateFrame("StatusBar", nil, tabContainer, "BackdropTemplate")
            tabBar:SetSize(95, CONFIG.TAB_HEIGHT - 2)

            if tabInfo.side == "right" then
                tabBar:SetPoint("RIGHT", -rightOffset, 0)
                rightOffset = rightOffset + 97
            else
                tabBar:SetPoint("LEFT", leftOffset, 0)
                leftOffset = leftOffset + 97
            end

            tabBar.key = tabInfo.key
            tabBar.isFullButton = false

            tabBar:SetStatusBarTexture(CONFIG.TEXTURES.STATUSBAR)
            tabBar:SetStatusBarColor(unpack(HDG_UIHelpers.STATE_INACTIVE))
            tabBar:SetMinMaxValues(0, 1)
            tabBar:SetValue(1)  -- Full bar for solid color

            -- Background/backdrop with 1px solid dim teal border
            tabBar:SetBackdrop({
                bgFile = CONFIG.TEXTURES.WHITE_BG,
                edgeFile = CONFIG.TEXTURES.WHITE_BG,
                tile = false,
                edgeSize = 1,
                insets = { left = 0, right = 0, top = 0, bottom = 0 }
            })
            -- Use scheme bg color if available
            local tabBgScheme = GetScheme()
            if tabBgScheme then
                tabBar:SetBackdropColor(tabBgScheme.bg.r, tabBgScheme.bg.g, tabBgScheme.bg.b, 0.3)
            else
                tabBar:SetBackdropColor(0.15, 0.15, 0.2, 0.3)
            end
            tabBar:SetBackdropBorderColor(tabBgScheme.border.r, tabBgScheme.border.g, tabBgScheme.border.b, 0.6)

            -- Tab icon
            local icon = tabBar:CreateTexture(nil, "OVERLAY")
            icon:SetSize(CONFIG.ICON_SIZE, CONFIG.ICON_SIZE)
            icon:SetPoint("LEFT", 2, 0)
            icon:SetTexture(tabInfo.icon)
            tabBar.icon = icon

            -- Tab text
            tabBar.text = tabBar:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            tabBar.text:SetPoint("LEFT", icon, "RIGHT", 4, 0)
            ApplyFont(tabBar.text, tabBgScheme, "small", 11)
            tabBar.text:SetText(tabInfo.name)

            -- Register for theme updates
            RegisterWidget(tabBar, "MainTab")
        end

        -- Create invisible button overlay for click handling
        local clickButton = CreateFrame("Button", nil, tabBar)
        clickButton:SetAllPoints(tabBar)
        clickButton:RegisterForClicks("LeftButtonUp")
        clickButton:SetScript("OnClick", function()
            Dispatch("SET_ACTIVE_TAB", { tab = tabInfo.key })
            HDG_UI.UpdateTabs()
        end)

        -- Tooltip (localized descriptions)
        local tooltipTexts = {
            recipes = L["TIP_TAB_RECIPES"] or "View all housing decor recipes",
            goblin = L["TIP_TAB_GOBLIN"] or "Profit analysis - find the most profitable crafts",
            preview = L["TIP_TAB_PREVIEW"] or "Preview decorations",
            acquisition = "Vendor shopping guide - find where to buy decorations",
            trainers = L["TIP_TAB_TRAINERS"] or "Find recipe trainers",
            characters = L["TIP_TAB_ALTS"] or "View profession data across all characters",
            data = L["TIP_TAB_DATA"] or "View farming history and statistics",
            config = L["TIP_TAB_CONFIG"] or "Configure addon settings and minimap icon"
        }

        clickButton:SetScript("OnEnter", function(self)
            -- Brighten on hover (only if not active)
            if GetUIState("activeTab") ~= tabInfo.key then
                if tabBar.isFullButton then
                    if tabBar.fullButtonTex then tabBar.fullButtonTex:SetAlpha(1.0) end
                else
                    tabBar:SetStatusBarColor(unpack(HDG_UIHelpers.STATE_HOVER))
                    if tabBar.icon then tabBar.icon:SetAlpha(1.0) end
                end
            end

            GameTooltip:SetOwner(self, HDG_UIHelpers.TOOLTIP_ANCHOR)
            GameTooltip:AddLine(C_Warning() .. tabInfo.name .. "|r", 1, 1, 1)
            GameTooltip:AddLine(tooltipTexts[tabInfo.key], 1, 1, 1)
            GameTooltip:Show()
        end)

        clickButton:SetScript("OnLeave", function(self)
            -- Restore color based on active state
            if GetUIState("activeTab") ~= tabInfo.key then
                if tabBar.isFullButton then
                    if tabBar.fullButtonTex then tabBar.fullButtonTex:SetAlpha(0.6) end
                else
                    tabBar:SetStatusBarColor(unpack(HDG_UIHelpers.STATE_INACTIVE))
                    if tabBar.icon then tabBar.icon:SetAlpha(0.6) end
                end
            end
            GameTooltip:Hide()
        end)

        -- Store both the bar and button for UpdateTabs function
        tabBar.statusBar = tabBar
        tabBar.button = clickButton

        table.insert(tabs, tabBar)
    end
    mainFrame.tabs = tabs

    -- Initialize tab modules
    HDG_LumberTracker.Init(mainFrame)

    -- Initialize tab modules with mainFrame reference
    if privateDB.HDG_RecipesTab then
        privateDB.HDG_RecipesTab:Init(mainFrame)
        privateDB.HDG_RecipesTab:Create()
    end

    if privateDB.HDG_AltsTab then
        privateDB.HDG_AltsTab.Init(mainFrame)
        privateDB.HDG_AltsTab.Create()
    end

    if privateDB.HDG_ConfigTab then
        privateDB.HDG_ConfigTab.Init(mainFrame)
        privateDB.HDG_ConfigTab.Create()
    end

    if privateDB.HDG_DataTab then
        privateDB.HDG_DataTab.Init(mainFrame)
        privateDB.HDG_DataTab.CreatePanel()
    end

    if privateDB.HDG_GoblinTab then
        privateDB.HDG_GoblinTab.Init(mainFrame)
        privateDB.HDG_GoblinTab.Create()
    end

    -- Trainers placeholder frame (actual content handled by HDG_Trainers module)
    HDG_UI.CreateTrainersPanel()

    -- Initialize state
    if not GetUIState("activeTab") then
        Dispatch("SET_ACTIVE_TAB", { tab = "recipes" })
    end
    HDG_UI.UpdateTabs()

    -- Listen for theme changes to refresh tab colors
    local HDG = _G.HousingDecorGuide
    if HDG and HDG.EventBus then
        HDG.EventBus:Register("HDG_THEME_UPDATE", function()
            HDG_UI.UpdateTabs()
        end)
    end

    -- Footer with random Orc quote (after version text)
    local footerScheme = GetScheme()
    local footer = mainFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    footer:SetPoint("BOTTOMLEFT", 65, 6)  -- After version text
    footer:SetWidth(CONFIG.MAIN_FRAME_WIDTH - 330)  -- Leave room for house level on right
    footer:SetJustifyH("LEFT")
    footer:SetText(string.format(C_Accent() .. "Vamoose says:|r " .. C_Warning() .. "%s|r", currentQuote))
    ApplyFont(footer, footerScheme, "small")
    mainFrame.workflowFooter = footer

    -- House Level display (bottom right) - single line layout
    -- Layout: [XP bar] [XP text] [Level text]
    local houseLevelFrame = CreateFrame("Frame", nil, mainFrame)
    houseLevelFrame:SetSize(320, 20)
    houseLevelFrame:SetPoint("BOTTOMRIGHT", -10, 6)
    mainFrame.houseLevelFrame = houseLevelFrame

    -- XP text (far right)
    local xpScheme = GetScheme()
    local xpText = houseLevelFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    xpText:SetPoint("BOTTOMRIGHT", houseLevelFrame, "BOTTOMRIGHT", 0, 0)
    ApplyFont(xpText, xpScheme, "small")
    if xpScheme then
        xpText:SetTextColor(xpScheme.text_dim.r, xpScheme.text_dim.g, xpScheme.text_dim.b, xpScheme.text_dim.a)
    else
        xpText:SetTextColor(0.6, 0.6, 0.6)
    end
    xpText:SetJustifyH("RIGHT")
    xpText:SetText(C_Dim() .. "-- / -- XP|r")  -- Placeholder
    mainFrame.houseXpText = xpText

    -- House level text (to the left of XP text, same baseline)
    local houseLevelText = houseLevelFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    houseLevelText:SetPoint("BOTTOMRIGHT", xpText, "BOTTOMLEFT", -12, 0)
    houseLevelText:SetJustifyH("RIGHT")
    houseLevelText:SetText(C_Accent() .. "House Level|r " .. C_Dim() .. "--|r")  -- Placeholder
    ApplyFont(houseLevelText, xpScheme, "small")
    mainFrame.houseLevelText = houseLevelText

    -- Tooltip on hover
    houseLevelFrame:EnableMouse(true)
    houseLevelFrame:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_TOP")
        GameTooltip:SetText(C_Accent() .. "House Level|r", 1, 1, 1)
        GameTooltip:AddLine("Earn House XP by collecting new decor items.", 0.7, 0.7, 0.7, true)
        GameTooltip:AddLine(" ")
        GameTooltip:AddLine("Higher house levels unlock more decoration slots.", 0.7, 0.7, 0.7, true)
        GameTooltip:Show()
    end)
    houseLevelFrame:SetScript("OnLeave", GameTooltip_Hide)

    -- Initial update
    HDG_UI.UpdateHouseLevelDisplay()

    privateDB.mainFrame = mainFrame
end

-- CreateRecipePanel, CreateShoppingPanel, CreateMaterialsPanel moved to HDG_RecipesTab.lua

function HDG_UI.CreateTrainersPanel()
    local trainersFrame = CreateFrame("Frame", nil, mainFrame, "BackdropTemplate")
    trainersFrame:SetPoint("TOPLEFT", CONFIG.SPACING.PANEL_PADDING, -(CONFIG.BANNER_HEIGHT + CONFIG.TAB_HEIGHT + 8))
    trainersFrame:SetSize(CONFIG.MAIN_FRAME_WIDTH - (CONFIG.SPACING.PANEL_PADDING * 2), CONFIG.PANEL_HEIGHT)
    trainersFrame:SetBackdrop({
        bgFile = CONFIG.TEXTURES.WHITE_BG,
        edgeFile = CONFIG.TEXTURES.WHITE_BG,
        tile = false,
        edgeSize = 1,
        insets = { left = 0, right = 0, top = 0, bottom = 0 }
    })
    local trainersScheme = GetScheme()
    trainersFrame:SetBackdropColor(trainersScheme.panel.r, trainersScheme.panel.g, trainersScheme.panel.b, 0.6)
    trainersFrame:SetBackdropBorderColor(trainersScheme.border.r, trainersScheme.border.g, trainersScheme.border.b, trainersScheme.border.a)
    RegisterWidget(trainersFrame, "Panel")
    trainersFrame:Hide()
    mainFrame.trainersFrame = trainersFrame

    -- Trainers implementation details handled by HDG_Trainers module
end

-- CreateCharactersPanel and RefreshCharactersPanel moved to HDG_AltsTab.lua

function HDG_UI.RefreshCharactersPanel()
    -- Delegate to HDG_AltsTab module
    if privateDB.HDG_AltsTab and privateDB.HDG_AltsTab.Refresh then
        privateDB.HDG_AltsTab.Refresh()
    end
end

-- CreateConfigPanel moved to HDG_ConfigTab.lua (stub for compatibility)

function HDG_UI.UpdateTabs()
    local tabKey = GetUIState("activeTab") or "recipes"

    mainFrame.recipeFrame:Hide()
    mainFrame.shoppingFrame:Hide()
    mainFrame.materialsFrame:Hide()
    mainFrame.trainersFrame:Hide()
    mainFrame.charactersFrame:Hide()
    mainFrame.configFrame:Hide()
    if mainFrame.dataFrame then mainFrame.dataFrame:Hide() end
    if mainFrame.goblinFrame then mainFrame.goblinFrame:Hide() end
    if HDG_DecorPreview then HDG_DecorPreview:Hide() end
    if HDG_AcquisitionTab then HDG_AcquisitionTab:Hide() end
    if HDG_Trainers then HDG_Trainers:Hide() end

    -- Update tab bar wood sign background (HousingTheme only)
    local tabScheme = GetScheme()
    if mainFrame.tabBgTexture then
        if tabScheme and tabScheme.atlas and tabScheme.atlas.tabBarWoodSign then
            mainFrame.tabBgTexture:SetAtlas(tabScheme.atlas.tabBarWoodSign)
            mainFrame.tabBgTexture:Show()
        else
            mainFrame.tabBgTexture:Hide()
        end
    end

    -- Update tab visuals (StatusBar-based tabs)
    for _, tab in ipairs(mainFrame.tabs or {}) do
        if tab.key == tabKey then
            -- Active tab
            tab.isActive = true
            if tab.isFullButton then
                -- Full button tab: brighten the texture (no StatusBar/backdrop)
                if tab.fullButtonTex then
                    tab.fullButtonTex:SetAlpha(1.0)
                end
            else
                -- Normal tab: accent-tinted background with full text, full opacity icon
                if tabScheme then
                    tab:SetStatusBarColor(tabScheme.accent.r, tabScheme.accent.g, tabScheme.accent.b, 0.3)
                    tab:SetBackdropBorderColor(tabScheme.accent.r, tabScheme.accent.g, tabScheme.accent.b, 0.8)
                else
                    tab:SetStatusBarColor(unpack(HDG_UIHelpers.STATE_ACTIVE))
                    tab:SetBackdropBorderColor(unpack(HDG_UIHelpers.BORDER_COLOR_BRIGHT))
                end
                if tab.text then
                    if tabScheme then
                        tab.text:SetTextColor(tabScheme.text.r, tabScheme.text.g, tabScheme.text.b, tabScheme.text.a)
                    else
                        tab.text:SetTextColor(1.0, 1.0, 1.0, 1)
                    end
                end
                if tab.icon then tab.icon:SetAlpha(1.0) end  -- Full opacity for active tab
            end
        else
            -- Inactive tab
            tab.isActive = false
            if tab.isFullButton then
                -- Full button tab: dim the texture (no StatusBar/backdrop)
                if tab.fullButtonTex then
                    tab.fullButtonTex:SetAlpha(0.6)
                end
            else
                -- Normal tab: dim background, reduced icon opacity
                if tabScheme then
                    tab:SetStatusBarColor(tabScheme.bg.r, tabScheme.bg.g, tabScheme.bg.b, 0.6)
                    tab:SetBackdropBorderColor(tabScheme.border.r, tabScheme.border.g, tabScheme.border.b, 0.5)
                else
                    tab:SetStatusBarColor(unpack(HDG_UIHelpers.STATE_INACTIVE))
                    tab:SetBackdropBorderColor(unpack(HDG_UIHelpers.BORDER_COLOR_DIM))
                end
                if tab.text then
                    if tabScheme then
                        tab.text:SetTextColor(tabScheme.text_dim.r, tabScheme.text_dim.g, tabScheme.text_dim.b, tabScheme.text_dim.a)
                    else
                        tab.text:SetTextColor(0.7, 0.7, 0.7, 1)
                    end
                end
                if tab.icon then tab.icon:SetAlpha(0.6) end  -- Reduced opacity - keeps color but recedes
            end
        end
    end

    if tabKey == "recipes" then
        if HDG_RecipesTab then
            HDG_RecipesTab:Show()
        end
    elseif tabKey == "preview" then
        if HDG_DecorPreview then
            if not HDG_DecorPreview.initialized then
                HDG_DecorPreview:Init(CONFIG, mainFrame, privateDB)
                HDG_DecorPreview.initialized = true
            end
            HDG_DecorPreview:Show()
        end
    elseif tabKey == "acquisition" then
        if HDG_AcquisitionTab then
            if not HDG_AcquisitionTab.initialized then
                HDG_AcquisitionTab:Init(CONFIG, mainFrame, privateDB)
                HDG_AcquisitionTab.initialized = true
            end
            HDG_AcquisitionTab:Show()
        end
    elseif tabKey == "config" then
        mainFrame.configFrame:Show()
    elseif tabKey == "trainers" then
        if HDG_Trainers then
            if not HDG_Trainers.initialized then
                HDG_Trainers:Init(CONFIG, mainFrame, Data().PlayerHasProfession)
                HDG_Trainers.initialized = true
            end
            HDG_Trainers:Show()
        end
    elseif tabKey == "characters" then
        mainFrame.charactersFrame:Show()
        HDG_UI.RefreshCharactersPanel()
    elseif tabKey == "data" then
        local HDG_DataTab = privateDB.HDG_DataTab
        if HDG_DataTab then
            HDG_DataTab.Show()
        end
    elseif tabKey == "goblin" then
        local HDG_GoblinTab = privateDB.HDG_GoblinTab
        if HDG_GoblinTab then
            HDG_GoblinTab.Show()
        end
    end
end

-- Switch to a specific tab programmatically (for cross-tab navigation)
function HDG_UI.SwitchTab(tabKey)
    Dispatch("SET_ACTIVE_TAB", { tab = tabKey })
    HDG_UI.UpdateTabs()
end

-- Recipe rendering functions moved to HDG_RecipesTab.lua

function HDG_UI.RefreshUI()
    if not mainFrame or not mainFrame:IsShown() then return end

    -- Always refresh shopping list and materials (even if on different tab)
    -- This ensures materials update when adding items from Preview tab
    if privateDB.HDG_RecipesTab then
        privateDB.HDG_RecipesTab:RefreshShoppingList()
        privateDB.HDG_RecipesTab:RefreshMaterials()
    end

    -- Refresh active tab content
    local activeTab = GetUIState("activeTab")

    if activeTab == "recipes" then
        -- Full recipes refresh when on recipes tab
        if privateDB.HDG_RecipesTab then
            privateDB.HDG_RecipesTab:RefreshRecipes()
        end
    elseif activeTab == "preview" then
        -- v2.1.5: Refresh preview tab when collection status changes
        if privateDB.HDG_DecorPreview then
            privateDB.HDG_DecorPreview:RefreshList()
        end
    elseif activeTab == "trainers" and HDG_Trainers then
        HDG_Trainers:Refresh()
    elseif activeTab == "acquisition" then
        if HDG_AcquisitionTab and HDG_AcquisitionTab.RefreshList then
            HDG_AcquisitionTab:RefreshList()
        end
    end

    HDG_UI.RefreshLumberTracking()
end

-- Update lumber layout based on pin state
-- When NOT pinned: show embedded lumber frame at bottom of shopping panel
-- When pinned: hide embedded frame, show separate floating window
function HDG_UI.UpdateLumberLayout()
    if not mainFrame then return end

    local isPinned = GetUIState("lumberPinned")

    -- Handle embedded lumber frame visibility
    if mainFrame.lumberFrame then
        if isPinned then
            -- Hide embedded, show pinned
            mainFrame.lumberFrame:Hide()
            -- Extend scroll frame down since lumber frame is hidden
            if mainFrame.shoppingScroll then
                mainFrame.shoppingScroll:SetPoint("BOTTOMRIGHT", -26, 8)
            end
        else
            -- Show embedded, hide pinned
            mainFrame.lumberFrame:Show()
            -- Restore scroll frame position above lumber frame (dynamic based on lumber count)
            if mainFrame.shoppingScroll then
                local lumberReservedHeight = 24 + (#HDG_ExpansionData.LUMBER_ORDER * 18) + 8 + 8
                mainFrame.shoppingScroll:SetPoint("BOTTOMRIGHT", -26, lumberReservedHeight)
            end
            -- Refresh the embedded lumber content
            HDG_UI.RefreshEmbeddedLumber()
        end
    end

    -- Manage pinned widget visibility
    if isPinned then
        if HDG_LumberTracker and HDG_LumberTracker.ShowPinned then
            HDG_LumberTracker.ShowPinned()
        end
    else
        if HDG_LumberTracker and HDG_LumberTracker.HidePinned then
            HDG_LumberTracker.HidePinned()
        end
    end
end

-- Refresh embedded lumber frame content (used when not pinned)
function HDG_UI.RefreshEmbeddedLumber()
    if not mainFrame or not mainFrame.lumberContent then return end
    ClearScrollContent(mainFrame.lumberContent)

    local dataModule = Data()
    if not dataModule.CalculateShoppingListLumber then return end

    local shoppingLumber = dataModule.CalculateShoppingListLumber(GetShoppingList())
    local allLumber = dataModule.CalculateLumberNeeds(privateDB.professions or {})
    local expansionOrder = HDG_ExpansionData.LUMBER_ORDER
    local LUMBER_TYPES = dataModule.LUMBER_TYPES

    local yOffset = 0
    for _, lumberId in ipairs(expansionOrder) do
        local shoppingData = shoppingLumber[lumberId]
        local allData = allLumber[lumberId]
        local lumberInfo = LUMBER_TYPES[lumberId]

        -- Create row using the shared helper (no farming options for embedded panel)
        yOffset = HDG_UIHelpers.CreateLumberRow(mainFrame.lumberContent, lumberId, lumberInfo, shoppingData, allData, yOffset, nil)
    end
end

function HDG_UI.RefreshLumberTracking()
    if not mainFrame then return end

    -- Update lumber button text (in recipes tab) if it exists
    if mainFrame.lumberBtn and mainFrame.lumberBtn.UpdateText then
        mainFrame.lumberBtn.UpdateText()
    end

    -- Manage embedded vs pinned lumber display
    local isPinned = GetUIState("lumberPinned")

    -- Refresh embedded lumber content if visible (not pinned)
    if not isPinned and mainFrame.lumberFrame and mainFrame.lumberFrame:IsShown() then
        HDG_UI.RefreshEmbeddedLumber()
    end

    -- Refresh the independent pinned widget if visible
    if HDG_LumberTracker and HDG_LumberTracker.IsPinnedVisible and HDG_LumberTracker.IsPinnedVisible() then
        HDG_LumberTracker.RefreshPinned()
    end
end

-- ============================================================================
-- DELEGATION TO HDG_RecipesTab
-- These functions delegate to HDG_RecipesTab for the actual implementation
-- ============================================================================

function HDG_UI.RefreshProfessionTabs()
    if privateDB.HDG_RecipesTab then
        privateDB.HDG_RecipesTab:RefreshProfessionTabs()
    end
end

function HDG_UI.AddToShoppingList(recipe, skipRefresh)
    if privateDB.HDG_RecipesTab then
        privateDB.HDG_RecipesTab:AddToShoppingList(recipe, skipRefresh)
    end
end

function HDG_UI.RefreshShoppingList()
    if privateDB.HDG_RecipesTab then
        privateDB.HDG_RecipesTab:RefreshShoppingList()
    end
end

function HDG_UI.RefreshMaterials()
    if privateDB.HDG_RecipesTab then
        privateDB.HDG_RecipesTab:RefreshMaterials()
    end
end

function HDG_UI.AddAllMaterialsToAuctionator()
    if privateDB.HDG_RecipesTab then
        privateDB.HDG_RecipesTab:AddAllMaterialsToAuctionator()
    end
end

-- Toggle UI
function HDG_UI.Toggle()
    -- Combat safety: defer UI toggle until out of combat
    if InCombatLockdown() then
        print(C_Warning() .. "[Housing Decor Guide]|r Cannot toggle window during combat.")
        return
    end

    if not mainFrame then HDG_UI.CreateUI() end
    if mainFrame:IsShown() then
        -- If lumber is pinned, show the independent pinned widget when closing main window
        if GetUIState("lumberPinned") then
            HDG_LumberTracker.ShowPinned()
        end
        mainFrame:Hide()
    else
        mainFrame:Show()
        HDG_UI.RefreshUI()
    end
end

-- Open HDG with a specific profession filter (v1.9.5)
function HDG_UI.OpenWithProfession(professionName)
    -- Combat safety
    if InCombatLockdown() then
        print(C_Warning() .. "[Housing Decor Guide]|r Cannot open window during combat.")
        return
    end

    if not mainFrame then HDG_UI.CreateUI() end

    -- Set the profession filter (per-character)
    if professionName then
        local HDG_RecipesTab = privateDB.HDG_RecipesTab
        if HDG_RecipesTab and HDG_RecipesTab.SetProfessionFilter then
            HDG_RecipesTab.SetProfessionFilter(professionName)
        end
    end

    -- Ensure we're on the recipes tab
    Dispatch("SET_ACTIVE_TAB", { tab = "recipes" })

    mainFrame:Show()
    HDG_UI.RefreshUI()
end

-- ============================================================================
-- PROFESSION WINDOW INTEGRATION (v1.9.5, v2.0.5)
-- Adds "Decor Guide" and "Filter Decor" buttons to Blizzard's profession UI
-- ============================================================================

local professionButton = nil
local filterDecorButton = nil
local filterDecorActive = false  -- Track filter toggle state

-- Use centralized profession data from HDG_ExpansionData
local function GetCurrentProfessionName()
    if not C_TradeSkillUI.IsTradeSkillReady() then return nil end

    local professionInfo = C_TradeSkillUI.GetBaseProfessionInfo()
    if professionInfo and professionInfo.professionID then
        return HDG_ExpansionData.GetProfessionName(professionInfo.professionID)
    end
    return nil
end

-- Helper to create a teal-styled button
local function CreateTealButton(name, parent, width, text)
    local btn = CreateFrame("Button", name, parent, "BackdropTemplate")
    btn:SetSize(width, 22)
    btn:SetFrameStrata("HIGH")
    btn:SetFrameLevel(500)

    btn:SetBackdrop({
        bgFile = "Interface\\Buttons\\WHITE8x8",
        edgeFile = "Interface\\Buttons\\WHITE8x8",
        tile = false,
        edgeSize = 1,
        insets = { left = 0, right = 0, top = 0, bottom = 0 }
    })
    local tealScheme = GetScheme()
    if tealScheme then
        btn:SetBackdropColor(tealScheme.accent.r, tealScheme.accent.g, tealScheme.accent.b, 0.9)
        btn:SetBackdropBorderColor(tealScheme.accent.r, tealScheme.accent.g, tealScheme.accent.b, tealScheme.accent.a)
    else
        btn:SetBackdropColor(0.08, 0.45, 0.42, 0.9)  -- Teal background
        btn:SetBackdropBorderColor(0.1, 0.6, 0.55, 1)  -- Lighter teal border
    end

    local btnText = btn:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    btnText:SetPoint("CENTER", 0, 0)
    ApplyFont(btnText, tealScheme, "small")
    btnText:SetText(C_Text() .. text .. "|r")
    btn.text = btnText

    -- Mark as accent button and register for theme updates
    btn.isAccentButton = true
    RegisterWidget(btn, "AccentButton")

    return btn
end

local function CreateProfessionButtons()
    if professionButton then return end

    -- Check if buttons are enabled in settings
    if GetConfig("showProfessionButtons") == false then
        return
    end

    -- ProfessionsFrame is the retail profession UI
    local parentFrame = ProfessionsFrame
    if not parentFrame then return end

    -- Create "Decor Guide" button (opens HDG filtered to current profession)
    professionButton = CreateTealButton("HDG_ProfessionButton", parentFrame, 90, L["BTN_DECOR_GUIDE"] or "Decor Guide")
    professionButton:SetPoint("TOPRIGHT", parentFrame, "TOPRIGHT", -110, -1)

    professionButton:SetScript("OnClick", function()
        local profName = GetCurrentProfessionName()
        if profName and HDG_ExpansionData.GetProfessionID(profName) then
            HDG_UI.OpenWithProfession(profName)
        else
            HDG_UI.Toggle()
        end
    end)

    professionButton:SetScript("OnEnter", function(self)
        local hoverScheme = GetScheme()
        if hoverScheme then
            self:SetBackdropColor(hoverScheme.button_hover.r, hoverScheme.button_hover.g, hoverScheme.button_hover.b, hoverScheme.button_hover.a)
        else
            self:SetBackdropColor(0.1, 0.55, 0.5, 1)
        end
        GameTooltip:SetOwner(self, HDG_UIHelpers.TOOLTIP_ANCHOR)
        local profName = GetCurrentProfessionName()
        if profName and HDG_ExpansionData.GetProfessionID(profName) then
            GameTooltip:AddLine(C_Warning() .. "Open Decor Guide|r")
            GameTooltip:AddLine("Filtered to " .. profName .. " decor recipes", 0.7, 0.7, 0.7)
        else
            GameTooltip:AddLine(C_Warning() .. "Open Decor Guide|r")
            GameTooltip:AddLine("View all housing decor recipes", 0.7, 0.7, 0.7)
        end
        GameTooltip:Show()
    end)

    professionButton:SetScript("OnLeave", function(self)
        local leaveScheme = GetScheme()
        if leaveScheme then
            self:SetBackdropColor(leaveScheme.accent.r, leaveScheme.accent.g, leaveScheme.accent.b, 0.9)
        else
            self:SetBackdropColor(0.08, 0.45, 0.42, 0.9)
        end
        GameTooltip:Hide()
    end)

    -- Create "Filter Decor" button (filters profession window to House Decor)
    local filterDecorLabel = L["BTN_FILTER_DECOR"] or "Filter Decor"
    filterDecorButton = CreateTealButton("HDG_FilterDecorButton", parentFrame, 85, filterDecorLabel)
    filterDecorButton:SetPoint("RIGHT", professionButton, "LEFT", -4, 0)

    -- Helper to update filter button appearance based on state
    local function UpdateFilterButtonAppearance()
        local filterScheme = GetScheme()
        if filterDecorActive then
            -- Active state: brighter teal with warning border
            if filterScheme then
                filterDecorButton:SetBackdropColor(filterScheme.button_hover.r, filterScheme.button_hover.g, filterScheme.button_hover.b, filterScheme.button_hover.a)
                filterDecorButton:SetBackdropBorderColor(filterScheme.warning.r, filterScheme.warning.g, filterScheme.warning.b, filterScheme.warning.a)
            else
                filterDecorButton:SetBackdropColor(0.1, 0.55, 0.5, 1)
                filterDecorButton:SetBackdropBorderColor(0.99, 0.83, 0.22, 1)  -- Gold border when active
            end
            filterDecorButton.text:SetText(C_Warning() .. filterDecorLabel .. "|r")  -- Active
        else
            -- Inactive state: normal accent color
            if filterScheme then
                filterDecorButton:SetBackdropColor(filterScheme.accent.r, filterScheme.accent.g, filterScheme.accent.b, 0.9)
                filterDecorButton:SetBackdropBorderColor(filterScheme.accent.r, filterScheme.accent.g, filterScheme.accent.b, filterScheme.accent.a)
            else
                filterDecorButton:SetBackdropColor(0.08, 0.45, 0.42, 0.9)
                filterDecorButton:SetBackdropBorderColor(0.1, 0.6, 0.55, 1)
            end
            filterDecorButton.text:SetText(C_Text() .. filterDecorLabel .. "|r")  -- Inactive
        end
    end

    filterDecorButton:SetScript("OnClick", function()
        if C_TradeSkillUI and C_TradeSkillUI.SetRecipeItemNameFilter then
            if filterDecorActive then
                -- Clear the filter
                C_TradeSkillUI.SetRecipeItemNameFilter("")
                filterDecorActive = false
            else
                -- Apply the filter
                C_TradeSkillUI.SetRecipeItemNameFilter("House Decor")
                filterDecorActive = true
            end
            UpdateFilterButtonAppearance()
        end
    end)

    filterDecorButton:SetScript("OnEnter", function(self)
        if not filterDecorActive then
            local enterScheme = GetScheme()
            if enterScheme then
                self:SetBackdropColor(enterScheme.button_hover.r, enterScheme.button_hover.g, enterScheme.button_hover.b, enterScheme.button_hover.a)
            else
                self:SetBackdropColor(0.1, 0.55, 0.5, 1)
            end
        end
        GameTooltip:SetOwner(self, HDG_UIHelpers.TOOLTIP_ANCHOR)
        if filterDecorActive then
            GameTooltip:AddLine(C_Warning() .. "Clear Filter|r")
            GameTooltip:AddLine("Click to show all recipes again.", 1, 1, 1, true)
        else
            GameTooltip:AddLine(C_Warning() .. "Filter House Decor|r")
            GameTooltip:AddLine("Filters recipes to show only House Decor.", 1, 1, 1, true)
            GameTooltip:AddLine(" ")
            GameTooltip:AddLine(C_Dim() .. "Note: Select each expansion tab|r", 0.7, 0.7, 0.7, true)
            GameTooltip:AddLine(C_Dim() .. "to see all decor recipes.|r", 0.7, 0.7, 0.7, true)
        end
        GameTooltip:Show()
    end)

    filterDecorButton:SetScript("OnLeave", function(self)
        UpdateFilterButtonAppearance()
        GameTooltip:Hide()
    end)

    -- Hook into profession frame show/update for visibility
    parentFrame:HookScript("OnShow", function()
        -- Reset filter state when window opens (filter text is cleared by WoW)
        filterDecorActive = false
        UpdateFilterButtonAppearance()

        if GetConfig("showProfessionButtons") == false then
            if professionButton then professionButton:Hide() end
            if filterDecorButton then filterDecorButton:Hide() end
        else
            if professionButton then professionButton:Show() end
            if filterDecorButton then filterDecorButton:Show() end
        end
    end)
end

-- Function to update profession button visibility based on settings
function HDG_UI.UpdateProfessionButtonVisibility()
    if GetConfig("showProfessionButtons") == false then
        if professionButton then professionButton:Hide() end
        if filterDecorButton then filterDecorButton:Hide() end
    else
        if professionButton then professionButton:Show() end
        if filterDecorButton then filterDecorButton:Show() end
    end
end

-- Hook into profession frame loading
local professionHookFrame = CreateFrame("Frame")
professionHookFrame:RegisterEvent("ADDON_LOADED")
professionHookFrame:RegisterEvent("TRADE_SKILL_SHOW")
professionHookFrame:SetScript("OnEvent", function(self, event, arg1)
    if event == "ADDON_LOADED" and arg1 == "Blizzard_Professions" then
        -- Blizzard profession UI loaded, create our buttons
        C_Timer.After(0.1, CreateProfessionButtons)
    elseif event == "TRADE_SKILL_SHOW" then
        -- Profession window opened, ensure buttons exist
        if ProfessionsFrame then
            CreateProfessionButtons()
        end
    end
end)

-- Function to refresh the random quote
function HDG_UI.RefreshQuote()
    currentQuote = ORC_QUOTES[math.random(#ORC_QUOTES)]
    if mainFrame and mainFrame.workflowFooter then
        mainFrame.workflowFooter:SetText(string.format(C_Accent() .. "Vamoose says:|r " .. C_Warning() .. "%s|r", currentQuote))
    end
end

-- Cache for house info
local cachedHouseList = nil
local cachedHouseGUID = nil

-- Request house list (async - will fire PLAYER_HOUSE_LIST_UPDATED)
function HDG_UI.RequestHouseInfo()
    if C_Housing and C_Housing.GetPlayerOwnedHouses then
        pcall(C_Housing.GetPlayerOwnedHouses)
    end
end

-- Called when PLAYER_HOUSE_LIST_UPDATED fires
function HDG_UI.OnHouseListUpdated(houseInfoList)
    cachedHouseList = houseInfoList
    if houseInfoList and #houseInfoList > 0 then
        cachedHouseGUID = houseInfoList[1].houseGUID
        -- Now request the favor info (async - will fire HOUSE_LEVEL_FAVOR_UPDATED)
        if cachedHouseGUID and C_Housing and C_Housing.GetCurrentHouseLevelFavor then
            pcall(C_Housing.GetCurrentHouseLevelFavor, cachedHouseGUID)
        end
    else
        -- No houses - hide the display
        if mainFrame and mainFrame.houseLevelFrame then
            mainFrame.houseLevelFrame:Hide()
        end
    end
end

-- Called when HOUSE_LEVEL_FAVOR_UPDATED fires with favor data
function HDG_UI.OnHouseLevelFavorUpdated(houseLevelFavor)
    if not mainFrame or not mainFrame.houseLevelText then return end
    if not houseLevelFavor then
        mainFrame.houseLevelFrame:Hide()
        return
    end

    -- From Blizzard code: houseLevelFavor has houseGUID, houseLevel, houseFavor
    local currentLevel = houseLevelFavor.houseLevel or 1
    local currentXP = houseLevelFavor.houseFavor or 0

    -- Get max level
    local maxLevel = 50
    if C_Housing and C_Housing.GetMaxHouseLevel then
        local success, max = pcall(C_Housing.GetMaxHouseLevel)
        if success and max then maxLevel = max end
    end

    -- Get XP needed for next level (GetHouseLevelFavorForLevel returns a number directly)
    local xpForNextLevel = 0
    if currentLevel < maxLevel and C_Housing and C_Housing.GetHouseLevelFavorForLevel then
        local success, needed = pcall(C_Housing.GetHouseLevelFavorForLevel, currentLevel + 1)
        if success and needed then
            xpForNextLevel = needed
        end
    end

    -- Update level text
    if currentLevel >= maxLevel then
        mainFrame.houseLevelText:SetText(string.format(C_Accent() .. "House Level|r " .. C_Warning() .. "%d|r " .. C_Dim() .. "(Max)|r", currentLevel))
    else
        mainFrame.houseLevelText:SetText(string.format(C_Accent() .. "House Level|r " .. C_Warning() .. "%d|r", currentLevel))
    end

    -- Calculate XP progress for THIS level (not total)
    -- Need XP from previous level to current level
    local xpForCurrentLevel = 0
    if currentLevel > 0 and C_Housing and C_Housing.GetHouseLevelFavorForLevel then
        local success, needed = pcall(C_Housing.GetHouseLevelFavorForLevel, currentLevel)
        if success and needed then
            xpForCurrentLevel = needed
        end
    end

    -- Update XP text (always show current / threshold XP)
    -- At max level, xpForNextLevel will be 0, so use xpForCurrentLevel as the threshold
    local xpThreshold = xpForNextLevel > 0 and xpForNextLevel or xpForCurrentLevel
    mainFrame.houseXpText:SetText(string.format("%d / %d XP", currentXP, xpThreshold))

    mainFrame.houseLevelFrame:Show()
end

-- Legacy function for compatibility - just requests the data
function HDG_UI.UpdateHouseLevelDisplay()
    if not mainFrame or not mainFrame.houseLevelText then return end

    -- Check if C_Housing API is available
    if not C_Housing then
        if mainFrame.houseLevelFrame then
            mainFrame.houseLevelFrame:Hide()
        end
        return
    end

    -- Request house info (async)
    HDG_UI.RequestHouseInfo()
end

-- Register for PLAYER_ENTERING_WORLD to change quote and house level events
local quoteFrame = CreateFrame("Frame")
quoteFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
quoteFrame:RegisterEvent("PLAYER_HOUSE_LIST_UPDATED")
quoteFrame:RegisterEvent("HOUSE_LEVEL_FAVOR_UPDATED")
quoteFrame:RegisterEvent("HOUSE_LEVEL_CHANGED")
quoteFrame:SetScript("OnEvent", function(self, event, ...)
    if event == "PLAYER_ENTERING_WORLD" then
        HDG_UI.RefreshQuote()
        HDG_UI.UpdateHouseLevelDisplay()
    elseif event == "PLAYER_HOUSE_LIST_UPDATED" then
        -- Receives houseInfoList as first argument
        local houseInfoList = ...
        HDG_UI.OnHouseListUpdated(houseInfoList)
    elseif event == "HOUSE_LEVEL_FAVOR_UPDATED" then
        -- Receives houseLevelFavor as first argument
        local houseLevelFavor = ...
        HDG_UI.OnHouseLevelFavorUpdated(houseLevelFavor)
    elseif event == "HOUSE_LEVEL_CHANGED" then
        -- Level changed - request fresh data
        HDG_UI.UpdateHouseLevelDisplay()
    end
end)

-- Export UI module
_G.HDG_UI = HDG_UI
privateDB.RefreshUI = HDG_UI.RefreshUI
