-- rOrbs_ComboBar.lua
-- Roth_UI-style horizontal combo / class-point bar ("Legacy" style).
-- Uses rOrbs' own bundled media textures (Roth_UI not required).
--
-- DB keys used:
--   rOrbsDB.comboPointStyle     = "runes" | "combobar" | "model3d" | "hidden"  (default: "runes")
--   rOrbsDB.comboBarColor       = { r, g, b }                      (default: purple)
--   rOrbsDB.comboBarScale       = number                           (default: 0.70)
--   rOrbsDB.comboBarOffX        = number                           (default: 0)
--   rOrbsDB.comboBarOffY        = number                           (default: -130)
--   rOrbsDB.runePointsFillRTL   = bool                             (default: false; true = fill orbs R→L)
--
-- Exports: ns.ComboBar = { Show, Hide, ForceRefresh, UpdateColor, UpdateLayout }

local addonName, ns = ...

-- ── media ────────────────────────────────────────────────────────────────────
-- Use rOrbs' own media folder (Roth_UI is not required).
local MEDIA = "Interface\\AddOns\\rOrbs\\media\\"

local TEX_LEFT      = MEDIA.."combo_left"
local TEX_RIGHT     = MEDIA.."combo_right"
local TEX_BAR_BG    = MEDIA.."combo_bar_bg"
local TEX_ORB_BG    = MEDIA.."combo_orb_bg"
local TEX_ORB_FILL  = MEDIA.."combo_orb_fill1"
local TEX_ORB_BDR   = MEDIA.."combo_orb_border"
local TEX_ORB_GLOW  = MEDIA.."combo_orb_glow"
local TEX_ORB_HL    = MEDIA.."combo_orb_highlight"

-- ── constants ─────────────────────────────────────────────────────────────────
local MAX_POINTS    = 6          -- max slots to create
local SLOT_SIZE     = 64         -- texture tile size (native)
local COLOR_MAX_R, COLOR_MAX_G, COLOR_MAX_B = 1, 0, 0    -- red at max

-- Default accent color (Roth_UI combo default is a warm amber-orange)
local DEFAULT_COLOR = { r = 0.90, g = 0.50, b = 0.10 }

-- ── state ─────────────────────────────────────────────────────────────────────
local initialized   = false
local barFrame      = nil        -- parent container
local orbFrames     = {}         -- orb slot frames [1..MAX_POINTS]
local currentPow    = -1
local currentMax    = 0
local previewActive = false      -- true while preview button is active

-- ── power helper ──────────────────────────────────────────────────────────────
local function GetPowerType()
    local _, class = UnitClass("player")
    if class == "ROGUE" then
        return Enum.PowerType.ComboPoints
    elseif class == "DRUID" then
        if GetSpecialization() == 2 then
            return Enum.PowerType.ComboPoints
        end
    elseif class == "PALADIN" then
        return Enum.PowerType.HolyPower
    elseif class == "MONK" then
        if GetSpecialization() == 3 then
            return Enum.PowerType.Chi
        end
    elseif class == "WARLOCK" then
        local s = GetSpecialization()
        if s == 1 or s == 3 then
            return Enum.PowerType.SoulShards
        end
    elseif class == "MAGE" then
        if GetSpecialization() == 1 then
            return Enum.PowerType.ArcaneCharges
        end
    elseif class == "EVOKER" then
        return Enum.PowerType.Essence
    end
    return nil
end

-- ── color helpers ─────────────────────────────────────────────────────────────
local function GetBarColor()
    local c = rOrbsDB and rOrbsDB.comboBarColor
    if c and c.r then return c.r, c.g, c.b end
    return DEFAULT_COLOR.r, DEFAULT_COLOR.g, DEFAULT_COLOR.b
end

local function ApplyOrbColor(orb, isMax)
    local r, g, b
    if isMax then
        r, g, b = COLOR_MAX_R, COLOR_MAX_G, COLOR_MAX_B
    else
        r, g, b = GetBarColor()
    end
    orb.fill:SetVertexColor(r, g, b)
    orb.glow:SetVertexColor(r, g, b)
end

-- ── layout ────────────────────────────────────────────────────────────────────
-- offX/offY are stored as UIParent-pixel offsets from screen center.
-- barFrame uses SetScale(), so SetPoint offsets must be divided by scale
-- so that the stored pixel values stay correct regardless of bar scale.
local function ApplyLayout()
    if not barFrame then return end
    local scale = (rOrbsDB and rOrbsDB.comboBarScale) or 0.70
    local offX  = (rOrbsDB and rOrbsDB.comboBarOffX)  or 0
    local offY  = (rOrbsDB and rOrbsDB.comboBarOffY)  or -130
    barFrame:SetScale(scale)
    -- UIParent effective scale compensates for UI scaling settings.
    -- Dividing by barFrame's own scale converts anchor-space pixels
    -- into barFrame-space pixels (which is what SetPoint expects).
    local uiScale = UIParent:GetEffectiveScale()
    local factor  = uiScale / scale
    barFrame:ClearAllPoints()
    barFrame:SetPoint("CENTER", UIParent, "CENTER", offX * factor, offY * factor)
end

-- ── show / hide orbs for current active count ─────────────────────────────────
local function UpdateOrbVisuals(active, max)
    for i = 1, MAX_POINTS do
        local orb = orbFrames[i]
        if not orb then break end
        if i > max then
            orb:Hide()
        else
            orb:Show()
            local isActive
            if rOrbsDB and rOrbsDB.runePointsFillRTL then
                isActive = ((max - i + 1) <= active)
            else
                isActive = (i <= active)
            end
            local isMax    = (active == max)
            if isActive then
                orb.fill:Show()
                orb.glow:Show()
                orb.highlight:Show()
                ApplyOrbColor(orb, isMax)
            else
                orb.fill:Hide()
                orb.glow:Hide()
                orb.highlight:Hide()
            end
        end
    end

    -- Resize bar frame width to fit the current max
    -- Layout: left edge (SLOT_SIZE) + max orbs + right edge (SLOT_SIZE)
    barFrame:SetWidth(SLOT_SIZE * (max + 2))
end

-- ── main update ───────────────────────────────────────────────────────────────
local function OnUpdate()
    if not barFrame then return end

    -- While preview is active, OnUpdate must not hide the bar
    if previewActive then return end

    -- Hidden if style is not "combobar"
    local style = rOrbsDB and rOrbsDB.comboPointStyle
    if style ~= "combobar" then
        barFrame:Hide()
        currentPow = -1
        return
    end

    local powerType = GetPowerType()
    if not powerType then
        barFrame:Hide()
        currentPow = -1
        return
    end

    -- UnitPower / UnitPowerMax are safe to use in Lua (not secret values)
    local new = UnitPower("player", powerType)
    local max = UnitPowerMax("player", powerType)

    if max == 0 then
        barFrame:Hide()
        currentPow = -1
        return
    end

    if new == currentPow and max == currentMax then return end
    currentPow = new
    currentMax = max

    barFrame:Show()
    UpdateOrbVisuals(new, max)
end

-- ── ForceRefresh: structural reset (spec / login) ────────────────────────────
local function ForceRefresh()
    currentPow = -1
    currentMax = 0
    OnUpdate()
end

-- ── create the bar frame and orb slots ───────────────────────────────────────
local function CreateBarFrame()
    -- Parent to UIParent; we'll reanchor to HealthOrb in ApplyLayout once orbs spawn.
    barFrame = CreateFrame("Frame", "rOrbsComboBar", UIParent)
    barFrame:SetFrameStrata("MEDIUM")
    barFrame:SetFrameLevel(50)
    barFrame:SetHeight(SLOT_SIZE)
    barFrame:SetWidth(SLOT_SIZE * (MAX_POINTS + 2))
    barFrame:SetClampedToScreen(true)
    barFrame:Hide()

    -- Left edge
    local le = barFrame:CreateTexture(nil, "BACKGROUND", nil, -8)
    le:SetSize(SLOT_SIZE, SLOT_SIZE)
    le:SetPoint("LEFT", barFrame, "LEFT", 0, 0)
    le:SetTexture(TEX_LEFT)

    -- Right edge
    local re = barFrame:CreateTexture(nil, "BACKGROUND", nil, -8)
    re:SetSize(SLOT_SIZE, SLOT_SIZE)
    re:SetPoint("RIGHT", barFrame, "RIGHT", 0, 0)
    re:SetTexture(TEX_RIGHT)

    -- Orb slots
    local osz = math.floor(SLOT_SIZE * 0.85)   -- visual orb size (matches Roth_UI)
    for i = 1, MAX_POINTS do
        local orb = CreateFrame("Frame", nil, barFrame)
        orb:SetSize(SLOT_SIZE, SLOT_SIZE)
        orb:SetPoint("LEFT", barFrame, "LEFT", i * SLOT_SIZE, 0)

        -- Slot background
        local barBg = orb:CreateTexture(nil, "BACKGROUND", nil, -8)
        barBg:SetSize(SLOT_SIZE, SLOT_SIZE)
        barBg:SetPoint("CENTER")
        barBg:SetTexture(TEX_BAR_BG)
        orb.barBg = barBg

        -- Orb dark background
        local bg = orb:CreateTexture(nil, "BACKGROUND", nil, -7)
        bg:SetSize(osz, osz)
        bg:SetPoint("CENTER")
        bg:SetTexture(TEX_ORB_BG)
        orb.bg = bg

        -- Orb fill (shown when active)
        local fill = orb:CreateTexture(nil, "BACKGROUND", nil, -6)
        fill:SetSize(osz, osz)
        fill:SetPoint("CENTER")
        fill:SetTexture(TEX_ORB_FILL)
        local r, g, b = GetBarColor()
        fill:SetVertexColor(r, g, b)
        fill:Hide()
        orb.fill = fill

        -- Orb border
        local bdr = orb:CreateTexture(nil, "BACKGROUND", nil, -5)
        bdr:SetSize(osz, osz)
        bdr:SetPoint("CENTER")
        bdr:SetTexture(TEX_ORB_BDR)
        orb.border = bdr

        -- Orb glow (shown when active, additive blend)
        local glow = orb:CreateTexture(nil, "BACKGROUND", nil, -4)
        glow:SetSize(osz, osz)
        glow:SetPoint("CENTER")
        glow:SetTexture(TEX_ORB_GLOW)
        glow:SetVertexColor(r, g, b)
        glow:SetBlendMode("BLEND")
        glow:Hide()
        orb.glow = glow

        -- Orb gloss / highlight (always visible)
        local hl = orb:CreateTexture(nil, "BACKGROUND", nil, -3)
        hl:SetSize(osz, osz)
        hl:SetPoint("CENTER")
        hl:SetTexture(TEX_ORB_HL)
        hl:Hide()
        orb.highlight = hl

        orbFrames[i] = orb
    end

    do
        local ovW = CreateFrame("Frame", nil, barFrame)
        ovW:SetAllPoints(barFrame)
        ovW:SetFrameLevel(barFrame:GetFrameLevel() + 60)
        local modTex = ovW:CreateTexture(nil, "OVERLAY", nil, 7)
        modTex:SetAllPoints(ovW)
        modTex:SetColorTexture(1, 1, 1)
        modTex:SetAlpha(0)
        ovW:SetScript("OnUpdate", function()
            if not barFrame or not barFrame:IsShown() then return end
            if rOrbsDB and rOrbsDB.orbDragLocked == true then
                modTex:Hide()
                return
            end
            local c = ns.cfg
            if not c or not c.framesUserplaced then return end
            local locked = c.framesLocked
            local sh, al = IsShiftKeyDown(), IsAltKeyDown()
            if locked then
                if al then
                    modTex:SetVertexColor(0.95, 0.2, 0.2)
                    modTex:SetAlpha(0.3)
                    modTex:Show()
                elseif sh then
                    modTex:SetVertexColor(0, 1, 0)
                    modTex:SetAlpha(0.22)
                    modTex:Show()
                else
                    modTex:Hide()
                end
            else
                modTex:Show()
                if al then
                    modTex:SetVertexColor(0.95, 0.2, 0.2)
                    modTex:SetAlpha(0.24)
                else
                    modTex:SetVertexColor(0, 1, 0)
                    modTex:SetAlpha(0.14)
                end
            end
        end)
    end

    -- ── Drag: Shift+Click = Move ──────────────────────────────────────────────
    barFrame:EnableMouse(true)
    barFrame:SetMovable(true)

    local _drag = false
    local _startX, _startY, _startOX, _startOY = 0, 0, 0, 0

    barFrame:SetScript("OnMouseDown", function(self, btn)
        if btn ~= "LeftButton" then return end
        if rOrbsDB and rOrbsDB.orbDragLocked then return end
        if not IsShiftKeyDown() then return end
        _drag = true
        local uisc = UIParent:GetEffectiveScale()
        local sx, sy = GetCursorPosition()
        _startX  = sx / uisc
        _startY  = sy / uisc
        _startOX = (rOrbsDB and rOrbsDB.comboBarOffX) or 0
        _startOY = (rOrbsDB and rOrbsDB.comboBarOffY) or -130
        self:SetScript("OnUpdate", function()
            if not _drag then self:SetScript("OnUpdate", nil); return end
            local cx, cy = GetCursorPosition()
            uisc = UIParent:GetEffectiveScale()
            -- Offsets stored as UIParent-pixel delta from screen center
            rOrbsDB.comboBarOffX = math.floor(_startOX + cx / uisc - _startX + 0.5)
            rOrbsDB.comboBarOffY = math.floor(_startOY + cy / uisc - _startY + 0.5)
            ApplyLayout()
        end)
    end)
    barFrame:SetScript("OnMouseUp", function(self)
        local hadDrag = _drag
        _drag = false
        self:SetScript("OnUpdate", nil)
        if hadDrag and rOrbsDB and rOrbsDB.snapToGrid then
            local g = 10
            rOrbsDB.comboBarOffX = math.floor((rOrbsDB.comboBarOffX or 0) / g + 0.5) * g
            rOrbsDB.comboBarOffY = math.floor((rOrbsDB.comboBarOffY or 0) / g + 0.5) * g
            ApplyLayout()
        end
        if ns.GUI and ns.GUI.RefreshValues then ns.GUI:RefreshValues() end
    end)

    -- Tooltip on hover
    barFrame:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_TOP")
        GameTooltip:AddLine("rOrbs Combo Bar", 0.9, 0.18, 0.18, 1, 1, 1)
        if rOrbsDB and rOrbsDB.orbDragLocked == true then
            local L = ns.L
            GameTooltip:AddLine(L and L["FRAME_DRAG_LOCKED_HINT"] or "Position locked in settings.", 0.75, 0.75, 0.75)
        else
            GameTooltip:AddLine("|cffffff00SHIFT + Drag|r to move", 1, 1, 1)
        end
        GameTooltip:Show()
    end)
    barFrame:SetScript("OnLeave", function() GameTooltip:Hide() end)
end

-- ── event listener ────────────────────────────────────────────────────────────
local function Initialize()
    if initialized then return end
    initialized = true

    CreateBarFrame()

    local evtFrame = CreateFrame("Frame", "rOrbsComboBarEvents", UIParent)
    evtFrame:RegisterEvent("UNIT_POWER_FREQUENT")
    evtFrame:RegisterEvent("UNIT_DISPLAYPOWER")
    evtFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
    evtFrame:RegisterEvent("PLAYER_TALENT_UPDATE")
    evtFrame:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED")
    evtFrame:RegisterEvent("UNIT_ENTERED_VEHICLE")
    evtFrame:RegisterEvent("UNIT_EXITED_VEHICLE")
    evtFrame:SetScript("OnEvent", function(_, event, unit)
        if event == "UNIT_POWER_FREQUENT" then
            if unit ~= "player" then return end
            OnUpdate()
        else
            ForceRefresh()
        end
    end)

    -- Apply initial layout after UI is ready
    C_Timer.After(1.5, function()
        ApplyLayout()
        ForceRefresh()
    end)

    ns.ComboBar = {
        Show          = function() if barFrame then barFrame:Show() end end,
        Hide          = function() if barFrame then barFrame:Hide() end end,
        ForceRefresh  = ForceRefresh,
        ApplyLayout   = ApplyLayout,
        ShowPreview   = function()
            if not barFrame then return end
            previewActive = true
            barFrame:SetFrameStrata("TOOLTIP")
            barFrame:SetFrameLevel(100)
            barFrame:SetAlpha(1)
            ApplyLayout()
            local max = (currentMax > 0) and currentMax or MAX_POINTS
            UpdateOrbVisuals(max, max)
            for i = 1, max do
                local orb = orbFrames[i]
                if orb then
                    orb:Show()
                    if orb.fill      then orb.fill:Show()      end
                    if orb.glow      then orb.glow:Show()      end
                    if orb.highlight then orb.highlight:Show() end
                    if orb.bg        then orb.bg:Show()        end
                    if orb.border    then orb.border:Show()    end
                    if orb.barBg     then orb.barBg:Show()     end
                end
            end
            barFrame:Show()
        end,
        HidePreview   = function()
            previewActive = false
            if barFrame then
                barFrame:SetFrameStrata("MEDIUM")
                barFrame:SetFrameLevel(50)
            end
            currentPow = -1
            currentMax = 0
            OnUpdate()
        end,
        UpdateColor   = function()
            -- Reapply current color to all orb textures
            local r, g, b = GetBarColor()
            for i = 1, MAX_POINTS do
                local orb = orbFrames[i]
                if orb then
                    orb.fill:SetVertexColor(r, g, b)
                    orb.glow:SetVertexColor(r, g, b)
                end
            end
            -- Re-run full update so max-color is reapplied if at max
            currentPow = -1
            OnUpdate()
        end,
    }
end

-- ── boot ─────────────────────────────────────────────────────────────────────
local boot = CreateFrame("Frame")
boot:RegisterEvent("PLAYER_LOGIN")
boot:SetScript("OnEvent", function(self)
    self:UnregisterAllEvents()
    C_Timer.After(0.8, Initialize)
end)
