--[[--------------------------------------------------------------------
  PaladinHolyPower – ui/components/theme.lua
  One source of truth for UI textures, tints, divider styling,
  and shared text/gradient helpers.
----------------------------------------------------------------------]]

local PHP = _G.PaladinHolyPower
if not PHP then return end

local Theme = {}
PHP.Theme = Theme

local WHITE_TEX  = "Interface\\Buttons\\WHITE8x8"
local PixelUtil  = _G.PixelUtil

-- Base path + default panel background texture (owned here)
local MEDIA_BASE = (PHP and PHP.MEDIA) or "Interface\\AddOns\\PaladinHolyPower\\media\\"
local DEFAULT_PANEL_TEX = MEDIA_BASE .. "icons\\background\\panel_1.png"

-- Live values (can be overridden via Theme.Register)
local _texture       = DEFAULT_PANEL_TEX
local _tint_root     = { 0.00, 0.00, 0.00, 0.00 }
local _tint_header   = { 0.79, 0.63, 0.20, 0.85 }
local _tint_sidebar  = { 0.79, 0.63, 0.20, 0.85 }
local _tint_content  = { 0.79, 0.63, 0.20, 0.85 }
local _accent_color  = { 0.79, 0.63, 0.20, 0.20 }
local _divider_thick = 1

-- ===== Default gradient endpoints (LEFT -> RIGHT) =====
-- (Do not change: callers can override through Register)
local _grad_left   = { 0.95, 0.90, 0.60 } -- #F2E699
local _grad_right  = { 1.00, 1.00, 1.00 } -- #FFFFFF

-- Registration --------------------------------------------------------

function Theme.Register(cfg)
  if type(cfg) ~= "table" then return end
  if cfg.texture        then _texture        = cfg.texture end
  if cfg.tint_root      then _tint_root      = cfg.tint_root end
  if cfg.tint_header    then _tint_header    = cfg.tint_header end
  if cfg.tint_sidebar   then _tint_sidebar   = cfg.tint_sidebar end
  if cfg.tint_content   then _tint_content   = cfg.tint_content end
  if cfg.accent_color   then _accent_color   = cfg.accent_color end
  if cfg.divider_thick  then _divider_thick  = cfg.divider_thick end
  if cfg.gradient_left  then _grad_left      = cfg.gradient_left end
  if cfg.gradient_right then _grad_right     = cfg.gradient_right end
end

-- Basic BG appliers ---------------------------------------------------

local function applyBG(frame, tint)
  if not frame or not frame.SetBackdrop then return end
  frame:SetBackdrop({ bgFile = _texture })
  frame:SetBackdropColor(tint[1], tint[2], tint[3], tint[4])
end

function Theme.ApplyRootBG(f)    applyBG(f, _tint_root)    end
function Theme.ApplyHeaderBG(f)  applyBG(f, _tint_header)  end
function Theme.ApplySidebarBG(f) applyBG(f, _tint_sidebar) end
function Theme.ApplyContentBG(f) applyBG(f, _tint_content) end

-- Dividers ------------------------------------------------------------

function Theme.NewDivider(parent, layer)
  local t = parent:CreateTexture(nil, layer or "OVERLAY")
  t:SetTexture(WHITE_TEX)
  t:SetColorTexture(_accent_color[1], _accent_color[2], _accent_color[3], _accent_color[4])
  if t.SetSnapToPixelGrid then t:SetSnapToPixelGrid(true); t:SetTexelSnappingBias(0) end
  return t
end

function Theme.RecolorDivider(tex)
  if not tex then return end
  tex:SetColorTexture(_accent_color[1], _accent_color[2], _accent_color[3], _accent_color[4])
end

function Theme.DrawH(line, frame, yFromTop)
  if not line or not frame then return end
  line:ClearAllPoints()
  if PixelUtil and PixelUtil.SetPoint then
    PixelUtil.SetPoint(line, "TOPLEFT",  frame, "TOPLEFT",  0, -yFromTop)
    PixelUtil.SetPoint(line, "TOPRIGHT", frame, "TOPRIGHT", 0, -yFromTop)
    PixelUtil.SetHeight(line, _divider_thick)
  else
    line:SetPoint("TOPLEFT",  frame, "TOPLEFT",  0, -yFromTop)
    line:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, -yFromTop)
    line:SetHeight(_divider_thick)
  end
end

function Theme.DrawV(line, frame, xFromLeft, yTop, yBottom)
  if not line or not frame then return end
  line:ClearAllPoints()
  if PixelUtil and PixelUtil.SetPoint then
    PixelUtil.SetPoint(line, "TOPLEFT",    frame, "TOPLEFT", xFromLeft, -yTop)
    PixelUtil.SetPoint(line, "BOTTOMLEFT", frame, "TOPLEFT", xFromLeft, -yBottom)
    PixelUtil.SetWidth(line, _divider_thick)
  else
    line:SetPoint("TOPLEFT",    frame, "TOPLEFT", xFromLeft, -yTop)
    line:SetPoint("BOTTOMLEFT", frame, "TOPLEFT", xFromLeft, -yBottom)
    line:SetWidth(_divider_thick)
  end
end

-- ========================== Text / Gradient ==========================

local function clamp01(x) if x < 0 then return 0 elseif x > 1 then return 1 else return x end end

-- Utility: hex/rgb
function Theme.RGBToHex(r, g, b)
  r = math.floor(clamp01(r or 1) * 255 + 0.5)
  g = math.floor(clamp01(g or 1) * 255 + 0.5)
  b = math.floor(clamp01(b or 1) * 255 + 0.5)
  return string.format("%02x%02x%02x", r, g, b)
end

function Theme.HexToRGB(hex)
  if not hex then return 1,1,1 end
  hex = tostring(hex):gsub("^#", "")
  if #hex ~= 6 then return 1,1,1 end
  local r = tonumber(hex:sub(1,2), 16) or 255
  local g = tonumber(hex:sub(3,4), 16) or 255
  local b = tonumber(hex:sub(5,6), 16) or 255
  return r/255, g/255, b/255
end

function Theme.LerpColor(a, b, t)
  t = clamp01(t or 0)
  return a[1] + (b[1] - a[1]) * t,
         a[2] + (b[2] - a[2]) * t,
         a[3] + (b[3] - a[3]) * t
end

-- Curve that HOLDS the left color longer (less white).
-- Short words => stronger hold; long words => nearly linear.
local function wow_word_curve(n)
  if n <= 4 then return 1.65      -- strong ease-in, delays highlight
  elseif n <= 8 then return 1.35  -- moderate
  else return 1.10                -- subtle on long labels
  end
end

-- Per-character LEFT→RIGHT gradient (keeps your palette).
-- "cap" softly prevents ever reaching full white so the bright end isn't dominant.
-- opts: reverse, safeAsciiOnly, gamma, cap
function Theme.GradientText(text, leftRGB, rightRGB, opts)
  if not text or text == "" then return "" end

  leftRGB  = leftRGB  or _grad_left
  rightRGB = rightRGB or _grad_right

  local n = #text
  local reverse = opts and opts.reverse
  local gamma   = (opts and opts.gamma) or wow_word_curve(n)
  local cap     = clamp01((opts and opts.cap) or 0.82) -- <=1; 0.82 keeps white subtle like the reference

  if opts and opts.safeAsciiOnly and text:find("[^\x20-\x7E]") then
    local hex = Theme.RGBToHex(leftRGB[1], leftRGB[2], leftRGB[3])
    return "|cff"..hex..text.."|r"
  end

  local L, R = leftRGB, rightRGB
  if reverse then L, R = rightRGB, leftRGB end

  local out = {}
  for i = 1, n do
    local t = (n == 1) and 1 or ((i - 1) / (n - 1))
    -- Hold base color longer, then approach highlight without hitting it.
    t = (t ^ gamma) * cap
    local r, g, b = Theme.LerpColor(L, R, t)
    out[i] = "|cff" .. Theme.RGBToHex(r, g, b) .. text:sub(i, i) .. "|r"
  end
  return table.concat(out)
end

-- Outline & shadow for readability (keeps your colors).
-- opts: sizeDelta, outline ("THICK"), reverse, safeAsciiOnly, gamma, cap, shadowA
local function apply_wow_edge(fs, opts)
  if not (fs and fs.SetFont and fs.GetFont) then return end

  local font, size, flags = fs:GetFont()
  size = tonumber(size) or 14
  if opts and opts.sizeDelta then size = size + tonumber(opts.sizeDelta) end

  local wantThick = (opts and opts.outline == "THICK") or false
  if flags and flags ~= "" then
    if wantThick and not string.find(flags, "THICKOUTLINE") then
      flags = flags:gsub("OUTLINE", "")
      flags = (flags == "" and "THICKOUTLINE") or (flags .. ",THICKOUTLINE")
    elseif not wantThick and not string.find(flags, "OUTLINE") then
      flags = flags .. ",OUTLINE"
    end
  else
    flags = wantThick and "THICKOUTLINE" or "OUTLINE"
  end
  fs:SetFont(font, size, flags)

  if fs.SetShadowColor then
    local a = (opts and opts.shadowA) or 0.85
    fs:SetShadowColor(0, 0, 0, a)
  end
  if fs.SetShadowOffset then
    fs:SetShadowOffset(1, -1)
  end
end

-- Apply gradient + edge.
-- opts: sizeDelta, outline ("THICK"), reverse, safeAsciiOnly, gamma, cap, shadowA
function Theme.ApplyGradientText(fs, text, leftRGB, rightRGB, opts)
  if not (fs and fs.SetText) then return end
  if fs.SetTextColor then fs:SetTextColor(1,1,1,1) end  -- neutralize vertex tint
  apply_wow_edge(fs, opts)
  fs:SetText(Theme.GradientText(text or "", leftRGB, rightRGB, opts))
end

-- Quick accessors
function Theme.White()           return {1,1,1} end
function Theme.GradientLeft()    return _grad_left end
function Theme.GradientRight()   return _grad_right end
function Theme.WhiteTex()        return WHITE_TEX end

-- Accessors -----------------------------------------------------------

function Theme.Texture()             return _texture end
function Theme.DefaultPanelTexture() return DEFAULT_PANEL_TEX end
function Theme.HeaderTint()          return _tint_header end
function Theme.SidebarTint()         return _tint_sidebar end
function Theme.ContentTint()         return _tint_content end
function Theme.RootTint()            return _tint_root end
function Theme.AccentColor()         return _accent_color end
function Theme.DividerThickness()    return _divider_thick end