-- ============================================================
-- MidnightQoL_QoL / RepBar.lua
-- Dedicated reputation bar styled to match the Experience bar.
-- Supports both Classic (GetWatchedFactionInfo) and
-- modern TWW/Dragonflight (C_Reputation.GetWatchedFactionData).
-- ============================================================

local API = MidnightQoLAPI

-- ── Defaults ──────────────────────────────────────────────────────────────────
local DEFAULTS = {
    repBarEnabled   = true,
    repBarWidth     = 600,
    repBarHeight    = 10,
    repBarX         = 0,
    repBarY         = -322,
    repBarShowText  = true,
    repBarFillR     = 0.8, repBarFillG = 0.2, repBarFillB = 1.0,
    repBarBgR       = 0.0, repBarBgG   = 0.0, repBarBgB   = 0.0, repBarBgA = 0.55,
    repBarPendingR  = 1.0, repBarPendingG = 0.85, repBarPendingB = 0.0,
}

local function GetDB()
    if not BuffAlertDB then return DEFAULTS end
    for k, v in pairs(DEFAULTS) do
        if BuffAlertDB[k] == nil then BuffAlertDB[k] = v end
    end
    return BuffAlertDB
end

-- ── Reputation API compatibility shim ─────────────────────────────────────────
-- Returns: name, repMin, repMax, repValue  OR  nil if nothing tracked.
local function GetWatchedFaction()
    -- Modern API (Dragonflight / TWW)
    if C_Reputation and C_Reputation.GetWatchedFactionData then
        local data = C_Reputation.GetWatchedFactionData()
        if data and data.name then
            -- currentReactionThreshold / nextReactionThreshold map to min/max
            local lo  = data.currentReactionThreshold or 0
            local hi  = data.nextReactionThreshold    or 0
            local val = data.currentStanding          or 0
            return data.name, lo, hi, val
        end
        return nil
    end
    -- Classic / Wrath fallback
    if GetWatchedFactionInfo then
        local name, _, _, _, _, repMin, repMax, repValue = GetWatchedFactionInfo()
        if name then return name, repMin, repMax, repValue end
    end
    return nil
end

-- ── Frame ─────────────────────────────────────────────────────────────────────
local repBar = CreateFrame("Frame", "MidnightQoLRepBar", UIParent)
repBar:SetFrameStrata("MEDIUM")
repBar:SetFrameLevel(10)
repBar:SetClampedToScreen(true)

-- Background
local repBg = repBar:CreateTexture(nil, "BACKGROUND")
repBg:SetAllPoints()
repBg:SetColorTexture(0, 0, 0, 0.55)

-- Pending rep fill (gold, behind main fill)
local repPendingFill = repBar:CreateTexture(nil, "BORDER", nil, 1)
repPendingFill:SetPoint("TOPLEFT"); repPendingFill:SetPoint("BOTTOMLEFT")
repPendingFill:SetColorTexture(1.0, 0.85, 0.0, 0.55)
repPendingFill:SetWidth(1)
repPendingFill:Hide()

-- Main rep fill
local repFill = repBar:CreateTexture(nil, "ARTWORK")
repFill:SetPoint("TOPLEFT"); repFill:SetPoint("BOTTOMLEFT")
repFill:SetColorTexture(0.8, 0.2, 1.0, 1)
repFill:SetWidth(1)

-- Shine / gloss overlay
local repGloss = repBar:CreateTexture(nil, "OVERLAY")
repGloss:SetAllPoints()
repGloss:SetColorTexture(1, 1, 1, 0.04)

-- Thin top-edge highlight line
local repEdge = repBar:CreateTexture(nil, "OVERLAY")
repEdge:SetPoint("TOPLEFT",  repBar, "TOPLEFT",  0, 0)
repEdge:SetPoint("TOPRIGHT", repBar, "TOPRIGHT", 0, 0)
repEdge:SetHeight(1)
repEdge:SetColorTexture(1, 1, 1, 0.18)

-- ── 10% Tick marks ────────────────────────────────────────────────────────────
local NUM_TICKS = 9
local repTicks = {}
for i = 1, NUM_TICKS do
    local tick = repBar:CreateTexture(nil, "OVERLAY")
    tick:SetWidth(1)
    tick:SetColorTexture(1, 1, 1, 0.35)
    repTicks[i] = tick
end

local function UpdateTicks()
    local barW = repBar:GetWidth()
    for i = 1, NUM_TICKS do
        repTicks[i]:ClearAllPoints()
        local xPos = barW * (i / 10)
        repTicks[i]:SetPoint("TOP",    repBar, "TOPLEFT",    xPos, 0)
        repTicks[i]:SetPoint("BOTTOM", repBar, "BOTTOMLEFT", xPos, 0)
    end
end

-- ── Text frame (HIGH strata so it always draws over fills) ────────────────────
local repTextFrame = CreateFrame("Frame", nil, UIParent)
repTextFrame:SetAllPoints(repBar)
repTextFrame:SetFrameStrata("HIGH")
repTextFrame:SetFrameLevel(100)

local repText = repTextFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
repText:SetPoint("CENTER", repTextFrame, "CENTER", 0, 0)
repText:SetJustifyH("CENTER")
repText:SetTextColor(1, 1, 1, 1)
repText:SetFont(repText:GetFont(), 9, "OUTLINE")

-- ── Pending rep from completed quests ─────────────────────────────────────────
local function GetPendingRepXP()
    if not C_QuestLog then return 0, 0 end
    local factionName = select(1, GetWatchedFaction() or "")
    if not factionName or factionName == "" then return 0, 0 end

    local totalRep, numQuests = 0, 0
    local numEntries = C_QuestLog.GetNumQuestLogEntries and C_QuestLog.GetNumQuestLogEntries() or 0
    for i = 1, numEntries do
        local info = C_QuestLog.GetInfo and C_QuestLog.GetInfo(i)
        if info and not info.isHeader and info.questID then
            if C_QuestLog.IsComplete and C_QuestLog.IsComplete(info.questID) then
                local numFactions = GetNumQuestLogRewardFactions and GetNumQuestLogRewardFactions(i) or 0
                for f = 1, numFactions do
                    local fname, rep = GetQuestLogRewardFactionInfo(f, i)
                    if fname and fname == factionName and rep and rep > 0 then
                        totalRep  = totalRep  + rep
                        numQuests = numQuests + 1
                        break
                    end
                end
            end
        end
    end
    return totalRep, numQuests
end

-- ── Apply settings ────────────────────────────────────────────────────────────
local function ApplyRepBarSettings()
    local db = GetDB()
    repBar:SetSize(db.repBarWidth, db.repBarHeight)
    repBar:ClearAllPoints()
    repBar:SetPoint("CENTER", UIParent, "CENTER", db.repBarX, db.repBarY)
    repFill:SetColorTexture(db.repBarFillR, db.repBarFillG, db.repBarFillB, 1)
    repBg:SetColorTexture(db.repBarBgR, db.repBarBgG, db.repBarBgB, db.repBarBgA)
    repPendingFill:SetColorTexture(db.repBarPendingR, db.repBarPendingG, db.repBarPendingB, 0.55)
    UpdateTicks()
end

-- ── Native bar suppression ────────────────────────────────────────────────────
local function HideNativeRepBar()
    if ReputationWatchBar        then ReputationWatchBar:SetAlpha(0) end
    if StatusTrackingBarManager  then StatusTrackingBarManager:SetAlpha(0) end
    for _, n in ipairs({ "ReputationWatchBar", "MainMenuBarRepFrame", "ReputationBar", "FactionWatchBar" }) do
        local f = _G[n]
        if f and f.SetAlpha then f:SetAlpha(0) end
    end
end

-- ── Core update ───────────────────────────────────────────────────────────────
local function UpdateRepBar()
    local db = GetDB()
    HideNativeRepBar()
    if not db.repBarEnabled then repBar:Hide(); return end

    local name, repMin, repMax, repValue = GetWatchedFaction()
    if not name then repBar:Hide(); return end

    repBar:Show()
    ApplyRepBarSettings()

    local range = repMax - repMin
    local cur   = repValue - repMin
    local pct   = (range > 0) and (cur / range) or 0
    local barW  = repBar:GetWidth()

    repFill:SetWidth(math.max(1, barW * pct))

    local pendingRep, pendingCount = GetPendingRepXP()
    if pendingRep > 0 then
        local pendingPct = math.min(1, (cur + pendingRep) / range)
        repPendingFill:SetWidth(math.max(1, barW * pendingPct))
        repPendingFill:Show()
    else
        repPendingFill:SetWidth(1)
        repPendingFill:Hide()
    end

    if db.repBarShowText then
        local pctDisplay = math.floor(pct * 100 + 0.5)
        local parts = { name .. "  " .. pctDisplay .. "%" }
        parts[#parts+1] = cur .. " / " .. range
        if pendingRep > 0 then
            parts[#parts+1] = "|cFFFFD700+" .. pendingRep .. " pending (" .. pendingCount .. "q)|r"
        end
        repText:SetText(table.concat(parts, "  ·  "))
        repText:Show()
    else
        repText:Hide()
    end
end

-- ── Tooltip ───────────────────────────────────────────────────────────────────
repBar:EnableMouse(true)
repBar:SetScript("OnEnter", function()
    local name, repMin, repMax, repValue = GetWatchedFaction()
    if not name then return end
    local range  = repMax - repMin
    local cur    = repValue - repMin
    local pct    = (range > 0) and math.floor(cur / range * 1000 + 0.5) / 10 or 0
    local needed = range - cur

    GameTooltip:SetOwner(repBar, "ANCHOR_TOP")
    GameTooltip:ClearLines()
    GameTooltip:AddLine(name, 0.8, 0.2, 1.0)
    GameTooltip:AddLine(cur .. " / " .. range .. "  (" .. pct .. "%)", 1, 1, 1)
    GameTooltip:AddLine(needed .. " rep to next rank", 0.8, 0.8, 0.8)

    local pendingRep, pendingCount = GetPendingRepXP()
    if pendingRep > 0 then
        GameTooltip:AddLine(" ", 1, 1, 1)
        GameTooltip:AddLine("Completed quests ready to turn in:", 1, 0.85, 0)
        GameTooltip:AddLine(pendingCount .. " quest" .. (pendingCount==1 and "" or "s") ..
            "  →  +" .. pendingRep .. " rep", 1, 1, 0.6)
        if (cur + pendingRep) >= range then
            GameTooltip:AddLine("Turning in would |cFF00FF00rank you up!|r", 0.9, 0.9, 0.9)
        end
    end
    GameTooltip:Show()
end)
repBar:SetScript("OnLeave", function() GameTooltip:Hide() end)

-- ── Drag (layout mode only) ───────────────────────────────────────────────────
repBar:SetMovable(true)
repBar:RegisterForDrag("LeftButton")
repBar:SetScript("OnDragStart", function(self)
    if not (API.IsLayoutMode and API.IsLayoutMode()) then return end
    self:StartMoving()
end)
repBar:SetScript("OnDragStop", function(self)
    self:StopMovingOrSizing()
    local db = GetDB()
    local cx = UIParent:GetWidth()  / 2
    local cy = UIParent:GetHeight() / 2
    local fx = self:GetLeft() + self:GetWidth()  / 2
    local fy = self:GetBottom() + self:GetHeight() / 2
    db.repBarX = math.floor(fx - cx + 0.5)
    db.repBarY = math.floor(fy - cy + 0.5)
    self:ClearAllPoints()
    self:SetPoint("CENTER", UIParent, "CENTER", db.repBarX, db.repBarY)
end)

-- ── Events ────────────────────────────────────────────────────────────────────
local repEvents = CreateFrame("Frame")
repEvents:RegisterEvent("PLAYER_LOGIN")
repEvents:RegisterEvent("UPDATE_FACTION")
repEvents:RegisterEvent("QUEST_LOG_UPDATE")
repEvents:RegisterEvent("CHAT_MSG_COMBAT_FACTION_CHANGE")

repEvents:SetScript("OnEvent", function(self, event)
    if event == "PLAYER_LOGIN" then
        C_Timer.After(0.5, function()
            HideNativeRepBar()
            UpdateRepBar()
        end)
    else
        UpdateRepBar()
    end
end)

-- ── Expose ────────────────────────────────────────────────────────────────────
API.repBar               = repBar
API.UpdateRepBar         = UpdateRepBar
API.ApplyRepBarSettings  = ApplyRepBarSettings

-- ── Register with Edit Layout ─────────────────────────────────────────────────
local repLayoutEvents = CreateFrame("Frame")
repLayoutEvents:RegisterEvent("PLAYER_LOGIN")
repLayoutEvents:SetScript("OnEvent", function(self)
    self:UnregisterEvent("PLAYER_LOGIN")
    C_Timer.After(0.6, function()
        if not API.RegisterLayoutHandles then return end
        API.RegisterLayoutHandles(function()
            local db = GetDB()
            if not db.repBarEnabled then return {} end
            return {
                {
                    label        = "Reputation Bar",
                    iconTex      = "Interface\\Icons\\Achievement_Reputation_01",
                    ox           = db.repBarX or 0,
                    oy           = db.repBarY or -322,
                    liveFrameRef = repBar,
                    saveCallback = function(nx, ny)
                        db.repBarX = nx; db.repBarY = ny
                        repBar:ClearAllPoints()
                        repBar:SetPoint("CENTER", UIParent, "CENTER", nx, ny)
                    end,
                    resizeCallback = function(nw, nh)
                        nw = math.max(100, math.floor(nw+0.5))
                        nh = math.max(2,   math.floor(nh+0.5))
                        db.repBarWidth = nw; db.repBarHeight = nh
                        repBar:SetSize(nw, nh)
                        UpdateTicks()
                        if _G["CSRepBarWidthEdit"]  then _G["CSRepBarWidthEdit"]:SetText(tostring(nw))  end
                        if _G["CSRepBarHeightEdit"] then _G["CSRepBarHeightEdit"]:SetText(tostring(nh)) end
                    end,
                }
            }
        end)
    end)
end)

API.Debug("[MidnightQoL] RepBar loaded.")
