local _, privateDB = ...

-- ============================================================================
-- ACHIEVEMENT SECTION for Data Tab
-- Housing achievements: Decor Collection, Community Coupons, Lumber Harvesting
-- ============================================================================

local CONFIG = privateDB.CONFIG
local HDG_AchievementSection = {}
privateDB.HDG_AchievementSection = HDG_AchievementSection

-- Convenience wrappers (same as DataTab uses)
local HDG = _G.HousingDecorGuide
local function GetScheme() return HDG.Theme.GetCurrentScheme() end
local function RegisterWidget(w, t) HDG.Theme.RegisterWidget(w, t) end
local function AddSectionStyle(fs, _) RegisterWidget(fs, "SectionHeader") end
local ApplyFont = function(fs, s, ft) HDG.Theme.ApplyFont(fs, s, ft) end

-- Module state
local dataFrame = nil -- set by Init()

-- ============================================================================
-- BAR WIDGET
-- ============================================================================

local ACH_BAR_TEX = "Interface\\PaperDollInfoFrame\\UI-Character-Skills-Bar"
local ACH_BORDER = "Interface\\PaperDollInfoFrame\\UI-Character-Skills-BarBorder"

local function CreateAchBar(parent, w, h, scheme)
    local f = CreateFrame("Frame", nil, parent)
    f:SetSize(w, h)
    -- Background (black, the "remaining" tone)
    local bg = f:CreateTexture(nil, "BACKGROUND")
    bg:SetAllPoints()
    bg:SetColorTexture(0, 0, 0, 0.5)
    -- Gray fill (total progress) -- bottom layer
    local gray = f:CreateTexture(nil, "BORDER")
    gray:SetTexture(ACH_BAR_TEX)
    gray:SetVertexColor(0.6, 0.6, 0.6, 1)
    gray:SetPoint("TOPLEFT")
    gray:SetPoint("BOTTOMLEFT")
    gray:SetWidth(1)
    gray:Hide()
    f._gray = gray
    -- Green fill (completed base) -- on top of gray
    local green = f:CreateTexture(nil, "BORDER", nil, 1)
    green:SetTexture(ACH_BAR_TEX)
    green:SetVertexColor(0.25, 0.65, 0.25, 0.9)
    green:SetPoint("TOPLEFT")
    green:SetPoint("BOTTOMLEFT")
    green:SetWidth(1)
    green:Hide()
    f._green = green
    -- 3-piece Blizzard border
    local bL = f:CreateTexture(nil, "ARTWORK")
    bL:SetTexture(ACH_BORDER)
    bL:SetTexCoord(0.007843, 0.043137, 0.193548, 0.774193)
    bL:SetPoint("TOPLEFT", -3, 3)
    bL:SetPoint("BOTTOMLEFT", -3, -3)
    bL:SetWidth(9)
    local bR = f:CreateTexture(nil, "ARTWORK")
    bR:SetTexture(ACH_BORDER)
    bR:SetTexCoord(0.043137, 0.007843, 0.193548, 0.774193)
    bR:SetPoint("TOPRIGHT", 3, 3)
    bR:SetPoint("BOTTOMRIGHT", 3, -3)
    bR:SetWidth(9)
    local bM = f:CreateTexture(nil, "ARTWORK")
    bM:SetTexture(ACH_BORDER)
    bM:SetTexCoord(0.113726, 0.1490196, 0.193548, 0.774193)
    bM:SetPoint("TOPLEFT", bL, "TOPRIGHT")
    bM:SetPoint("BOTTOMRIGHT", bR, "BOTTOMLEFT")
    -- Checkmark text (right-aligned inside bar)
    local text = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    text:SetPoint("RIGHT", -4, 0)
    text:SetJustifyH("RIGHT")
    if scheme then ApplyFont(text, scheme, "small") end
    f.text = text

    -- API: SetThreeTone(completedBase, currentQty, maxThreshold)
    -- Gray covers total progress from left; green overlays the completed base on top
    function f:SetThreeTone(base, qty, maxVal)
        if maxVal <= 0 then self._green:Hide(); self._gray:Hide(); return end
        local bw = self:GetWidth()
        -- Gray: total progress (qty/maxVal) from left
        self._gray:ClearAllPoints()
        self._gray:SetPoint("TOPLEFT")
        self._gray:SetPoint("BOTTOMLEFT")
        self._gray:SetWidth(math.max(1, bw * math.min(qty, maxVal) / maxVal))
        self._gray:SetVertexColor(0.6, 0.6, 0.6, 1)
        self._gray:Show()
        -- Green: completed base on top (base/maxVal) from left
        if base > 0 then
            self._green:ClearAllPoints()
            self._green:SetPoint("TOPLEFT")
            self._green:SetPoint("BOTTOMLEFT")
            self._green:SetWidth(math.max(1, bw * base / maxVal))
            self._green:SetVertexColor(0.25, 0.65, 0.25, 1)
            self._green:Show()
        else
            self._green:Hide()
        end
    end

    -- API: SetFull(r, g, b, a) -- fills entire bar with one color
    function f:SetFull(r, g, b, a)
        self._green:ClearAllPoints()
        self._green:SetPoint("TOPLEFT")
        self._green:SetPoint("BOTTOMRIGHT")
        self._green:SetVertexColor(r, g, b, a)
        self._green:Show()
        self._gray:Hide()
    end

    -- API: SetSingleFill(qty, maxVal, r, g, b, a) -- one-color partial fill
    function f:SetSingleFill(qty, maxVal, r, g, b, a)
        if maxVal <= 0 or qty <= 0 then self._green:Hide(); self._gray:Hide(); return end
        local bw = self:GetWidth()
        self._green:ClearAllPoints()
        self._green:SetPoint("TOPLEFT")
        self._green:SetPoint("BOTTOMLEFT")
        self._green:SetWidth(math.max(1, bw * math.min(qty, maxVal) / maxVal))
        self._green:SetVertexColor(r, g, b, a)
        self._green:Show()
        self._gray:Hide()
    end

    return f
end

-- ============================================================================
-- ROW FACTORY
-- ============================================================================

local ACH_ROW_H = 18
local ACH_BAR_W = 280   -- bar width for single-column rows
local ACH_LBAR_W = 120  -- bar width for lumber 2-column rows

local function MakeAchRow(achieveID, parent, barW, rowW, ctW, scheme)
    local row = CreateFrame("Frame", nil, parent)
    row:SetSize(rowW, ACH_ROW_H)
    row._achieveID = achieveID
    local bar = CreateAchBar(row, barW, ACH_ROW_H - 4, scheme)
    bar:SetPoint("LEFT", 0, 0)
    row._bar = bar
    -- Count/check text (between bar and name)
    local ct = row:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    ct:SetPoint("LEFT", bar, "RIGHT", 6, 0)
    ct:SetWidth(ctW)
    ct:SetJustifyH("LEFT")
    ApplyFont(ct, scheme, "small")
    row._ct = ct
    -- Name text (after count)
    local nt = row:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    nt:SetPoint("LEFT", ct, "RIGHT", 4, 0)
    nt:SetPoint("RIGHT", row, "RIGHT", -2, 0)
    nt:SetJustifyH("LEFT")
    nt:SetWordWrap(false)
    ApplyFont(nt, scheme, "small")
    row._nt = nt
    -- Tooltip on whole row
    row:EnableMouse(true)
    row:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        local ok, _, name, _, _, _, _, _, desc = pcall(GetAchievementInfo, self._achieveID)
        if ok and name then
            GameTooltip:SetText(name, 1, 0.82, 0.3)
            if desc and desc ~= "" then GameTooltip:AddLine(desc, 0.7, 0.7, 0.7, true) end
        else
            GameTooltip:SetText("Achievement #" .. self._achieveID, 0.5, 0.5, 0.5)
        end
        GameTooltip:Show()
    end)
    row:SetScript("OnLeave", function() GameTooltip:Hide() end)
    return row
end

-- ============================================================================
-- CREATE (called from DataTab.CreatePanel)
-- ============================================================================

function HDG_AchievementSection.Create(scrollChild, yOffset, df)
    dataFrame = df
    local scheme = GetScheme()

    -- Section title
    local achTitle = scrollChild:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    achTitle:SetPoint("TOPLEFT", 4, yOffset)
    ApplyFont(achTitle, scheme, "header")
    achTitle:SetText("Housing Achievements")
    if scheme then
        achTitle:SetTextColor(scheme.text_header.r, scheme.text_header.g, scheme.text_header.b, scheme.text_header.a)
    else
        achTitle:SetTextColor(0.99, 0.83, 0.22, 1)
    end
    achTitle.isHeader = true
    AddSectionStyle(achTitle, scrollChild)
    RegisterWidget(achTitle, "PanelTitle")

    yOffset = yOffset - 22

    -- Container for all achievement groups
    local achContainer = CreateFrame("Frame", nil, scrollChild)
    achContainer:SetPoint("TOPLEFT", 4, yOffset)
    achContainer:SetSize(CONFIG.MAIN_FRAME_WIDTH - 80, 1) -- height set by Relayout
    dataFrame.achContainer = achContainer
    dataFrame.achCollapsed = {}
    dataFrame.achGroupList = {}

    -- Group definitions
    local achGroupDefs = {
        { key = "decor", label = "Decor Collection", items = HDG_ExpansionData.DECOR_ACHIEVEMENTS },
        { key = "coupon", label = "Community Coupons", items = HDG_ExpansionData.COUPON_ACHIEVEMENTS },
        { key = "lumber", label = "Lumber Harvesting" },
    }
    local achHalfWidth = math.floor((CONFIG.MAIN_FRAME_WIDTH - 90) / 2)

    for _, gdef in ipairs(achGroupDefs) do
        local group = { key = gdef.key, rows = {} }
        dataFrame.achCollapsed[gdef.key] = false

        -- Clickable group header
        local header = CreateFrame("Button", nil, achContainer)
        header:SetSize(CONFIG.MAIN_FRAME_WIDTH - 80, 20)
        local arrow = CreateFrame("Button", nil, header)
        arrow:SetSize(16, 16)
        arrow:SetPoint("LEFT", 2, 0)
        arrow:SetNormalAtlas("common-button-collapseExpand-down")
        arrow:SetPushedAtlas("common-button-collapseExpand-down-pressed")
        arrow:SetHighlightAtlas("common-button-collapseExpand-hover")
        group.arrow = arrow
        local hlabel = header:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        hlabel:SetPoint("LEFT", arrow, "RIGHT", 2, 0)
        ApplyFont(hlabel, scheme, "body")
        if scheme then
            hlabel:SetTextColor(scheme.text_header.r, scheme.text_header.g, scheme.text_header.b, 1)
        else
            hlabel:SetTextColor(0.99, 0.83, 0.22, 1)
        end
        hlabel:SetText(gdef.label)
        group.hlabel = hlabel
        local hcount = header:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        hcount:SetPoint("RIGHT", -4, 0)
        hcount:SetJustifyH("RIGHT")
        ApplyFont(hcount, scheme, "small")
        group.hcount = hcount
        -- Thin line under header
        local hSep = header:CreateTexture(nil, "ARTWORK")
        hSep:SetHeight(1)
        hSep:SetPoint("BOTTOMLEFT", 0, -1)
        hSep:SetPoint("BOTTOMRIGHT", 0, -1)
        if scheme then
            hSep:SetColorTexture(scheme.border.r, scheme.border.g, scheme.border.b, 0.3)
        else
            hSep:SetColorTexture(0.3, 0.3, 0.35, 0.3)
        end
        group.header = header

        -- Row dimensions per group type
        local barW = (gdef.key == "lumber") and ACH_LBAR_W or ACH_BAR_W
        local rowW = (gdef.key == "lumber") and achHalfWidth or (CONFIG.MAIN_FRAME_WIDTH - 90)
        local ctW = (gdef.key == "lumber") and 60 or 80

        -- Create individual achievement rows
        if gdef.key == "lumber" then
            local lumberOrder = HDG_ExpansionData.LUMBER_ORDER
            local lumberTypes = HDG_ExpansionData.LUMBER_TYPES
            for idx, lumberId in ipairs(lumberOrder) do
                local info = lumberTypes[lumberId]
                if info and info.achieveID then
                    local row = MakeAchRow(info.achieveID, achContainer, barW, rowW, ctW, scheme)
                    row._lumberId = lumberId
                    row._expansion = info.expansion
                    row._col = ((idx - 1) % 2)
                    row._gridRow = math.floor((idx - 1) / 2)
                    table.insert(group.rows, row)
                end
            end
        else
            local prevThr = 0
            for _, a in ipairs(gdef.items) do
                local row = MakeAchRow(a.id, achContainer, barW, rowW, ctW, scheme)
                row._threshold = a.threshold
                row._prevThreshold = prevThr
                table.insert(group.rows, row)
                prevThr = a.threshold
            end
        end

        -- Toggle collapse on click
        header:SetScript("OnClick", function()
            dataFrame.achCollapsed[gdef.key] = not dataFrame.achCollapsed[gdef.key]
            HDG_AchievementSection.Relayout()
        end)

        table.insert(dataFrame.achGroupList, group)
    end

    -- Separator after achievements (drawn on scrollChild, below the container)
    local achSep = scrollChild:CreateTexture(nil, "ARTWORK")
    achSep:SetHeight(1)
    local sepY = yOffset -- will be repositioned by Relayout via contentParent
    achSep:SetPoint("TOPLEFT", 4, sepY)
    achSep:SetPoint("TOPRIGHT", -4, sepY)
    if scheme then
        achSep:SetColorTexture(scheme.border.r, scheme.border.g, scheme.border.b, 0.5)
    else
        achSep:SetColorTexture(0.3, 0.3, 0.35, 0.5)
    end

    -- Wrapper frame for all content below achievements
    local contentParent = CreateFrame("Frame", nil, scrollChild)
    contentParent:SetPoint("TOPLEFT", 0, -(22 + 1 + 8)) -- placeholder; Relayout fixes
    contentParent:SetPoint("RIGHT", scrollChild)
    contentParent:SetHeight(2000)
    dataFrame.contentParent = contentParent

    -- Store achHalfWidth for layout use
    dataFrame._achHalfWidth = achHalfWidth

    return contentParent -- DataTab uses this as new scrollChild
end

-- ============================================================================
-- RELAYOUT (positions groups/bars, updates container + scroll heights)
-- ============================================================================

function HDG_AchievementSection.Relayout()
    if not dataFrame or not dataFrame.achGroupList then return end
    local achHalfWidth = dataFrame._achHalfWidth
    local ay = 0
    for _, group in ipairs(dataFrame.achGroupList) do
        group.header:ClearAllPoints()
        group.header:SetPoint("TOPLEFT", 0, ay)
        ay = ay - 22
        if dataFrame.achCollapsed[group.key] then
            group.arrow:SetNormalAtlas("common-button-collapseExpand-up")
            group.arrow:SetPushedAtlas("common-button-collapseExpand-up-pressed")
        else
            group.arrow:SetNormalAtlas("common-button-collapseExpand-down")
            group.arrow:SetPushedAtlas("common-button-collapseExpand-down-pressed")
        end
        if dataFrame.achCollapsed[group.key] then
            for _, row in ipairs(group.rows) do row:Hide() end
        else
            if group.key == "lumber" then
                local vi = 0
                for _, row in ipairs(group.rows) do
                    if row._invalid then
                        row:Hide()
                    else
                        row:Show()
                        row:ClearAllPoints()
                        local col = vi % 2
                        local gr = math.floor(vi / 2)
                        row:SetPoint("TOPLEFT", col * (achHalfWidth + 8), ay - gr * ACH_ROW_H)
                        vi = vi + 1
                    end
                end
                ay = ay - math.ceil(vi / 2) * ACH_ROW_H
            else
                for _, row in ipairs(group.rows) do
                    if row._invalid then
                        row:Hide()
                    else
                        row:Show()
                        row:ClearAllPoints()
                        row:SetPoint("TOPLEFT", 0, ay)
                        ay = ay - ACH_ROW_H
                    end
                end
            end
        end
        ay = ay - 6
    end
    local newH = math.abs(ay) + 4
    dataFrame.achContainer:SetHeight(newH)
    -- Reposition content below and update scroll area
    local sc = dataFrame.scrollChild
    local cp = dataFrame.contentParent
    if cp and sc then
        cp:ClearAllPoints()
        cp:SetPoint("TOPLEFT", sc, "TOPLEFT", 0, -(22 + newH + 8))
        cp:SetPoint("RIGHT", sc)
        sc:SetHeight(22 + newH + 8 + cp:GetHeight())
    end
end

-- ============================================================================
-- REFRESH (called from DataTab.Show and ACHIEVEMENT_EARNED)
-- ============================================================================

function HDG_AchievementSection.Refresh()
    if not dataFrame or not dataFrame.achGroupList then return end

    local MUTED_GREEN = { 0, 0.6, 0, 0.8 }
    local DONE_GREEN = { 0.25, 0.65, 0.25, 0.9 }
    local CHECK = "|TInterface\\AchievementFrame\\UI-Achievement-Criteria-Check:0|t"

    -- Helper: update a single decor/coupon row
    local function UpdateStandardRow(row)
        local ok, _, name, _, completed = pcall(GetAchievementInfo, row._achieveID)
        if not ok or not name then row:Hide(); row._invalid = true; return false, false end
        row._invalid = false
        local bar = row._bar
        local cOk, _, _, _, qty, reqQty = pcall(GetAchievementCriteriaInfo, row._achieveID, 1)
        qty = (cOk and qty) or 0
        local threshold = (cOk and reqQty and reqQty > 0) and reqQty or row._threshold
        if completed then
            bar:SetFull(unpack(DONE_GREEN))
            bar.text:Show()
            bar.text:SetText("|cFF55DD55" .. CHECK .. "|r")
            row._ct:SetText("|cFF55DD55" .. threshold .. " / " .. threshold .. "|r")
            row._nt:SetText("|cFF55DD55" .. name .. "|r")
            return true, true
        else
            local prevThr = row._prevThreshold or 0
            if prevThr > 0 and qty >= prevThr then
                bar:SetThreeTone(prevThr, qty, threshold)
            else
                bar:SetSingleFill(qty, threshold, unpack(MUTED_GREEN))
            end
            bar.text:Hide()
            row._ct:SetText(HDG.Theme.C_Dim() .. qty .. " / " .. threshold .. "|r")
            row._nt:SetText(HDG.Theme.C_Text() .. name .. "|r")
            return true, false
        end
    end

    -- Decor Collection
    local decorGroup = dataFrame.achGroupList[1]
    local decorDone, decorTotal = 0, 0
    for _, row in ipairs(decorGroup.rows) do
        local valid, done = UpdateStandardRow(row)
        if valid then decorTotal = decorTotal + 1 end
        if done then decorDone = decorDone + 1 end
    end
    decorGroup.hcount:SetText(
        (decorDone >= decorTotal and decorTotal > 0)
            and ("|cFF55DD55" .. decorDone .. "/" .. decorTotal .. "|r")
            or (HDG.Theme.C_Dim() .. decorDone .. "/" .. decorTotal .. "|r"))
    if not dataFrame._achFirstRefreshDone and decorDone >= decorTotal and decorTotal > 0 then
        dataFrame.achCollapsed.decor = true
        -- (relayout happens at end of Refresh)
    end

    -- Community Coupons
    local couponGroup = dataFrame.achGroupList[2]
    local couponDone, couponTotal = 0, 0
    for _, row in ipairs(couponGroup.rows) do
        local valid, done = UpdateStandardRow(row)
        if valid then couponTotal = couponTotal + 1 end
        if done then couponDone = couponDone + 1 end
    end
    couponGroup.hcount:SetText(
        (couponDone >= couponTotal and couponTotal > 0)
            and ("|cFF55DD55" .. couponDone .. "/" .. couponTotal .. "|r")
            or (HDG.Theme.C_Dim() .. couponDone .. "/" .. couponTotal .. "|r"))
    if not dataFrame._achFirstRefreshDone and couponDone >= couponTotal and couponTotal > 0 then
        dataFrame.achCollapsed.coupon = true
        -- (relayout happens at end of Refresh)
    end

    -- Lumber Harvesting
    local lumberGroup = dataFrame.achGroupList[3]
    local lumberDone, lumberTotal = 0, 0
    for _, row in ipairs(lumberGroup.rows) do
        lumberTotal = lumberTotal + 1
        local qty, reqQty, completed = HDG_ExpansionData.GetLumberAchievementProgress(row._lumberId)
        local shortName = HDG_ExpansionData.GetLumberMaterialName(row._lumberId) or "???"
        local bar = row._bar
        if completed then
            lumberDone = lumberDone + 1
            bar:SetFull(unpack(DONE_GREEN))
            bar.text:Show()
            bar.text:SetText("|cFF55DD55" .. CHECK .. "|r")
            local t = reqQty or 250
            row._ct:SetText("|cFF55DD55" .. t .. " / " .. t .. "|r")
            row._nt:SetText("|cFF55DD55" .. shortName .. "|r")
        elseif qty then
            local expColor = HDG_ExpansionData.GetColor(row._expansion)
            bar:SetSingleFill(qty, reqQty or 250, expColor[1], expColor[2], expColor[3], 0.8)
            bar.text:Hide()
            row._ct:SetText(HDG.Theme.C_Dim() .. qty .. " / " .. (reqQty or 250) .. "|r")
            row._nt:SetText(HDG.Theme.C_Text() .. shortName .. "|r")
        end
    end
    lumberGroup.hcount:SetText(
        (lumberDone >= lumberTotal and lumberTotal > 0)
            and ("|cFF55DD55" .. lumberDone .. "/" .. lumberTotal .. "|r")
            or (HDG.Theme.C_Dim() .. lumberDone .. "/" .. lumberTotal .. "|r"))
    if not dataFrame._achFirstRefreshDone and lumberDone >= lumberTotal and lumberTotal > 0 then
        dataFrame.achCollapsed.lumber = true
        -- (relayout happens at end of Refresh)
    end

    dataFrame._achFirstRefreshDone = true
    HDG_AchievementSection.Relayout()
end
