-- HousingDecorGuide/UI/Projects/HDG_BudgetStrip.lua
-- Persistent header strip for the Projects tab: Rooms budget + Decor budget meters.
-- Live-updates from C_HousingLayout / C_HousingDecor budget APIs.

local _, privateDB = ...

local M = {}

local STRIP_HEIGHT = 28

local function _createMeter(parent, label, x)
    local f = CreateFrame("Frame", nil, parent)
    f:SetSize(180, STRIP_HEIGHT - 4)
    f:SetPoint("LEFT", parent, "LEFT", x, 0)

    local lbl = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    lbl:SetPoint("LEFT", f, "LEFT", 0, 0)
    lbl:SetText(label)
    lbl:SetTextColor(0.6, 0.7, 0.8, 1)

    local bar = CreateFrame("StatusBar", nil, f)
    bar:SetSize(80, 8)
    bar:SetPoint("LEFT", lbl, "RIGHT", 6, 0)
    bar:SetStatusBarTexture("Interface\\TargetingFrame\\UI-StatusBar")
    bar:SetStatusBarColor(0.43, 0.72, 0.55, 1)   -- green
    bar:SetMinMaxValues(0, 100)
    bar:SetValue(0)

    local bg = bar:CreateTexture(nil, "BACKGROUND")
    bg:SetAllPoints()
    bg:SetColorTexture(0, 0, 0, 0.5)

    -- Plan-mode overlay segment. Renders as a translucent purple bar on
    -- top of the actual statusbar; width tracks the planned count. When
    -- planned > max, the bar caps at 100% and the text adds "+N over".
    local plan = bar:CreateTexture(nil, "OVERLAY")
    plan:SetHeight(8)
    plan:SetPoint("TOPLEFT",    bar, "TOPLEFT",    0, 0)
    plan:SetPoint("BOTTOMLEFT", bar, "BOTTOMLEFT", 0, 0)
    plan:SetColorTexture(0.78, 0.50, 0.95, 0.75)
    plan:Hide()

    local txt = f:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    txt:SetPoint("LEFT", bar, "RIGHT", 6, 0)
    txt:SetText("0 / 0")

    f.bar  = bar
    f.txt  = txt
    f.plan = plan
    return f
end

local function _currentHouseID()
    local f = UnitFactionGroup("player")
    if f == "Alliance" then return "house:alliance"
    elseif f == "Horde" then return "house:horde" end
    return nil
end

-- Planned room budget = Σ shape.budget (DB2 HouseRoom.WeightCost) over every
-- room recorded under the current house. Matches the cost-weighted total
-- that C_HousingLayout.GetSpentPlacementBudget() returns at runtime.
local function _plannedRoomCount()
    local store = _G.HousingDecorGuide and _G.HousingDecorGuide.Store
    if not (store and store.GetState) then return 0 end
    local houseID = _currentHouseID()
    if not houseID then return 0 end
    local rooms = store:GetState().projects and store:GetState().projects.rooms or {}
    local Atlas = privateDB.HDG_RoomShapeAtlas
    local prefix = houseID .. ":"
    local total = 0
    for id, room in pairs(rooms) do
        if id:sub(1, #prefix) == prefix then
            local cost = (Atlas and Atlas.GetBudget and Atlas.GetBudget(room.shape)) or 0
            total = total + cost
        end
    end
    return total
end

local function _activeMode()
    local store = _G.HousingDecorGuide and _G.HousingDecorGuide.Store
    return (store and store.GetState and store:GetState().projects
            and store:GetState().projects.ui and store:GetState().projects.ui.activeMode)
           or "reflect"
end

function M:Update(roomSpent, roomMax, decorSpent, decorMax, decorCount)
    if not self.frame then return end
    local function pct(s, mx) return mx > 0 and math.min(100, (s / mx) * 100) or 0 end
    local mode = _activeMode()

    -- Rooms meter — always shown. Plan mode adds the planned overlay.
    self.roomMeter.bar:SetValue(pct(roomSpent or 0, roomMax or 0))
    local plan = self.roomMeter.plan
    if mode == "plan" and plan then
        local planned = _plannedRoomCount()
        local mx = roomMax or 0
        local barW = self.roomMeter.bar:GetWidth() or 80
        local fillW = (mx > 0) and math.min(barW, barW * (planned / mx)) or barW
        plan:SetWidth(math.max(0.001, fillW))
        plan:Show()
        if planned > mx then
            self.roomMeter.txt:SetText(string.format(
                "%d / %d  |cffff8c5c|A:common-icon-forwardarrow:10:10|a%d (+%d)|r",
                roomSpent or 0, mx, planned, planned - mx))
        elseif planned ~= (roomSpent or 0) then
            self.roomMeter.txt:SetText(string.format(
                "%d / %d  |cffd6a9ff|A:common-icon-forwardarrow:10:10|a%d|r",
                roomSpent or 0, mx, planned))
        else
            self.roomMeter.txt:SetText(string.format("%d / %d", roomSpent or 0, mx))
        end
    else
        if plan then plan:Hide() end
        self.roomMeter.txt:SetText(string.format("%d / %d", roomSpent or 0, roomMax or 0))
    end

    -- Decor budget — always shown.
    self.decorBudgetMeter.bar:SetValue(pct(decorSpent or 0, decorMax or 0))
    self.decorBudgetMeter.txt:SetText(string.format("%d / %d", decorSpent or 0, decorMax or 0))

    -- Decor count — Reflect only. Plan mode hides this meter to keep
    -- focus on what's editable (rooms, room budget, decor budget).
    if self.decorCountMeter then
        if mode == "plan" then
            self.decorCountMeter.frame:Hide()
        else
            self.decorCountMeter.frame:Show()
            self.decorCountMeter.txt:SetText(string.format("%d", decorCount or 0))
        end
    end
end

function M:Refresh()
    local roomMax    = (C_HousingLayout and C_HousingLayout.GetRoomPlacementBudget())  or 0
    local roomSpent  = (C_HousingLayout and C_HousingLayout.GetSpentPlacementBudget()) or 0
    local decorMax   = (C_HousingDecor  and C_HousingDecor.GetMaxPlacementBudget())    or 0
    local decorSpent = (C_HousingDecor  and C_HousingDecor.GetSpentPlacementBudget())  or 0
    local decorCount = (C_HousingDecor  and C_HousingDecor.GetNumDecorPlaced
                        and C_HousingDecor.GetNumDecorPlaced())                        or 0
    self:Update(roomSpent, roomMax, decorSpent, decorMax, decorCount)
end

function M:Create(parent)
    self.frame = CreateFrame("Frame", nil, parent)
    self.frame:SetHeight(STRIP_HEIGHT)
    self.frame:SetPoint("TOPLEFT", parent, "TOPLEFT", 0, 0)
    self.frame:SetPoint("TOPRIGHT", parent, "TOPRIGHT", 0, 0)

    local bg = self.frame:CreateTexture(nil, "BACKGROUND")
    bg:SetAllPoints()
    bg:SetColorTexture(0.08, 0.16, 0.25, 0.4)

    self.roomMeter        = _createMeter(self.frame, "Rooms",        12)
    self.decorBudgetMeter = _createMeter(self.frame, "Decor budget", 320)
    -- Decor (count) meter is just a label + number — no bar (the count has
    -- no obvious cap). Built inline so it can be hidden in Plan mode.
    do
        local f = CreateFrame("Frame", nil, self.frame)
        f:SetSize(140, STRIP_HEIGHT - 4)
        f:SetPoint("LEFT", self.frame, "LEFT", 560, 0)

        local lbl = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        lbl:SetPoint("LEFT", f, "LEFT", 0, 0)
        lbl:SetText("Decor")
        lbl:SetTextColor(0.6, 0.7, 0.8, 1)

        local txt = f:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        txt:SetPoint("LEFT", lbl, "RIGHT", 6, 0)
        txt:SetText("0")

        self.decorCountMeter = { frame = f, txt = txt }
    end

    -- Live update on relevant events
    self.frame:RegisterEvent("HOUSE_LEVEL_FAVOR_UPDATED")
    self.frame:RegisterEvent("HOUSING_NUM_DECOR_PLACED_CHANGED")
    self.frame:RegisterEvent("HOUSING_LAYOUT_ROOM_RECEIVED")
    self.frame:RegisterEvent("HOUSING_LAYOUT_ROOM_REMOVED")
    self.frame:RegisterEvent("HOUSING_LAYOUT_ROOM_RETURNED")
    self.frame:SetScript("OnEvent", function() self:Refresh() end)
    self.frame:SetScript("OnShow", function() self:Refresh() end)

    -- Plan-mode signals: refresh whenever the plan changes or mode toggles.
    local g = _G.HousingDecorGuide
    local bus = g and g.EventBus
    if bus and bus.Register then
        bus:Register("HDG_PROJECT_ROOM_UPDATED",      function() self:Refresh() end)
        bus:Register("HDG_PROJECTS_MODE_CHANGED",     function() self:Refresh() end)
        bus:Register("HDG_PROJECTS_TOPOLOGY_UPDATED", function() self:Refresh() end)
    end

    self:Refresh()
    return self.frame
end

privateDB.HDG_BudgetStrip = M
