--[[--------------------------------------------------------------------
  PaladinHolyPower - tracker/holy_power/display.lua
  Holy Power bar (5 pips) — RENDERER ONLY

  • events.lua decides visibility of the FRAME.
  • This file creates the frame, lays out icons/bar, colors, pulse, Masque.
  • Important: Bar style uses child textures that start hidden — we
    explicitly show/hide them here based on the current style.
----------------------------------------------------------------------]]

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

-- ------------------------------ Masque ------------------------------
local MS           = PHP.MasqueSupport
local MASQUE_KEY   = "PHP_HolyPowerBar"
local MASQUE_TITLE = "Holy Power Bar"

local function Masque_EnableSafe(buttons, icons)
  if not MS then return end
  if MS.EnableGroup then MS:EnableGroup(MASQUE_KEY, MASQUE_TITLE) end
  if MS.AddButton and buttons and icons then
    for i = 1, #buttons do
      if buttons[i] and icons[i] then
        MS:AddButton(MASQUE_KEY, buttons[i], icons[i])
      end
    end
  end
  if     MS.ReskinNow    then MS:ReskinNow(MASQUE_KEY)
  elseif MS.RefreshGroup then MS:RefreshGroup(MASQUE_KEY)
  elseif MS.UpdateGroup  then MS:UpdateGroup(MASQUE_KEY)
  end
end

local function Masque_ReskinSafe()
  if MS and MS.ReskinNow then MS:ReskinNow(MASQUE_KEY) end
end

-- --------------------------- SharedMedia ----------------------------
local LSM = LibStub and LibStub("LibSharedMedia-3.0", true)
local SM  = PHP.SharedMedia
local function FetchStatusbarTexture(name)
  if not name or name == "" or name == "Solid Color" then return nil end
  local tex = SM and SM.Fetch and SM:Fetch("statusbar", name)
  if (not tex) and LSM and LSM.Fetch then tex = LSM:Fetch("statusbar", name) end
  return tex
end

-- ------------------------------ Assets ------------------------------
local DEFAULT_CUSTOM_ICON = 1445240
local NUM_ICONS           = 5

local MEDIA_BASE = (PHP and PHP.MEDIA) or "Interface\\AddOns\\PaladinHolyPower\\media\\"
local runeTextures = {
  MEDIA_BASE .. "icons\\paladin_runes\\hp_rune1.png",
  MEDIA_BASE .. "icons\\paladin_runes\\hp_rune2.png",
  MEDIA_BASE .. "icons\\paladin_runes\\hp_rune3.png",
  MEDIA_BASE .. "icons\\paladin_runes\\hp_rune4.png",
  MEDIA_BASE .. "icons\\paladin_runes\\hp_rune5.png",
}

-- ------------------------------ Helpers -----------------------------
local function S() return PHP.settings and PHP.settings.HP or nil end
local function ActiveHP(conf)
  if not conf then return {} end
  conf.styles = conf.styles or {}
  local style = conf.style or "default"
  conf.styles[style] = conf.styles[style] or {}
  return conf.styles[style]
end

local function GetHP()
  return (UnitPower and UnitPower("player", 9)) or 0
end

-- Preview flag (events.lua sets it true if EditMode OR HP Bar subtab active)
local function IsPreview()
  return (type(PHP.HPBar_IsPreview) == "function") and (PHP.HPBar_IsPreview() == true) or false
end

local function ClampZoom(z)
  z = tonumber(z) or 0
  if z >= .5 then return .49 elseif z < 0 then return 0 else return z end
end
local function ApplyZoom(tex, z)
  z = ClampZoom(z)
  if tex and tex.SetTexCoord then tex:SetTexCoord(z, 1 - z, z, 1 - z) end
end
local function ResetTex(tex)
  if tex and tex.SetTexCoord then tex:SetTexCoord(0, 1, 0, 1) end
end

local function WaveY(i, amp)
  amp = tonumber(amp) or 0
  if amp == 0 then return 0 end
  local oddUp = (amp >= 0)
  local isOdd = (i % 2 == 1)
  return ((isOdd == oddUp) and 1 or -1) * math.abs(amp)
end

-- Smooth pulse
local function EnsurePulse(owner)
  if not owner or not owner.CreateAnimationGroup then return nil end
  if owner.Pulse then return owner.Pulse end

  local ag = owner:CreateAnimationGroup()
  ag:SetLooping("NONE")

  local s1 = ag:CreateAnimation("Scale")
  s1:SetOrder(1); s1:SetDuration(0.16); s1:SetScale(1.12, 1.12)
  if s1.SetSmoothing then s1:SetSmoothing("OUT") end
  if s1.SetOrigin   then s1:SetOrigin("CENTER", 0, 0) end

  local s2 = ag:CreateAnimation("Scale")
  s2:SetOrder(2); s2:SetDuration(0.20); s2:SetScale(1/1.12, 1/1.12)
  if s2.SetSmoothing then s2:SetSmoothing("IN") end
  if s2.SetOrigin   then s2:SetOrigin("CENTER", 0, 0) end

  owner.Pulse = ag
  return ag
end
local function PlayPulse(owner)
  local ag = EnsurePulse(owner)
  if ag then ag:Stop(); ag:Play() end
end

local function ApplyStyle(frame, conf, active)
  local chosenIcon = active.customIcon or conf.customIcon or DEFAULT_CUSTOM_ICON
  for i = 1, NUM_ICONS do
    frame.iconsCustom[i]:SetTexture(chosenIcon)
    frame.iconsDefault[i]:SetTexture(runeTextures[i])
  end
end

-- ============================== Create ==============================
function PHP.EnsureHPBarFrame()
  if PHP.tracker5BarFrame then return PHP.tracker5BarFrame end

  local frame = CreateFrame("Frame", "PaladinHolyPower5Bar", UIParent, "BackdropTemplate")
  frame:SetPoint("CENTER", UIParent, "CENTER", 0, -215)
  frame:SetFrameStrata("MEDIUM")
  frame:SetFrameLevel(10)
  frame:EnableMouse(false)
  frame:Hide()  -- prevent flash after /reload; events.lua will show/hide

  frame.pips, frame.buttons, frame.iconsCustom, frame.iconsDefault = {}, {}, {}, {}
  frame.segBG, frame.segFill, frame.segDiv = {}, {}, {}
  frame._masqueInit, frame._lastHP, frame._lastStyle = false, nil, nil

  -- Segmented bar textures
  for i = 1, NUM_ICONS do
    local bg   = frame:CreateTexture(nil, "BACKGROUND")
    local fill = frame:CreateTexture(nil, "ARTWORK")
    bg:SetColorTexture(0.1, 0.1, 0.1, 0.8)
    fill:SetColorTexture(1, 1, 1, 1)
    bg:Hide(); fill:Hide()
    frame.segBG[i], frame.segFill[i] = bg, fill
  end
  for i = 1, NUM_ICONS - 1 do
    local d = frame:CreateTexture(nil, "OVERLAY")
    d:SetColorTexture(0, 0, 0, 1); d:Hide()
    frame.segDiv[i] = d
  end

  -- Icons
  for i = 1, NUM_ICONS do
    local pip = CreateFrame("Frame", nil, frame, "BackdropTemplate")
    pip:SetFrameLevel(frame:GetFrameLevel() + 3)
    pip:EnableMouse(false)

    local btn = CreateFrame("Button", nil, frame)
    btn:SetFrameStrata("MEDIUM")
    btn:SetFrameLevel(frame:GetFrameLevel() + 5)
    btn:EnableMouse(false)

    local iconC = btn:CreateTexture(nil, "ARTWORK"); iconC:SetAllPoints(btn); iconC:Hide(); btn.Icon = iconC
    local iconD = pip:CreateTexture(nil, "ARTWORK"); iconD:SetAllPoints(pip); iconD:Hide()

    frame.pips[i], frame.buttons[i]            = pip, btn
    frame.iconsCustom[i], frame.iconsDefault[i] = iconC, iconD

    EnsurePulse(btn); EnsurePulse(pip)
  end

  if MS and not frame._masqueInit then
    Masque_EnableSafe(frame.buttons, frame.iconsCustom)
    frame._masqueInit = true
  end

  if PHP.EditHandle and PHP.EditHandle.AttachMovablePanel then
    PHP.EditHandle.AttachMovablePanel(
      frame,
      function() return S() end,
      { default = { x = 0, y = -215 }, title = "Holy Power", dbKeys = { "HP", "x", "y" } }
    )
  end

  PHP.tracker5BarFrame = frame
  return frame
end

-- ============================== Layout ==============================
local function LayoutBar(frame, active, style)
  local spacing = tonumber(active.iconSpacing) or 0
  local vwave   = tonumber(active.verticalWave) or 0

  if style == "custom_bar" then
    local w = tonumber(active.width) or 40
    local h = tonumber(active.height) or 20
    frame:SetSize((w * NUM_ICONS) + (spacing * (NUM_ICONS - 1)), h)

    for i = 1, NUM_ICONS do
      local bg, fill = frame.segBG[i], frame.segFill[i]
      local x, y     = (i - 1) * (w + spacing), WaveY(i, vwave)
      bg:ClearAllPoints();   bg:SetPoint("LEFT", frame, "LEFT", x, y); bg:SetSize(w, h)
      fill:ClearAllPoints(); fill:SetPoint("LEFT", bg, "LEFT", 0, 0);  fill:SetSize(w, h)
    end

    if spacing <= 0 then
      for i = 1, NUM_ICONS - 1 do
        local div = frame.segDiv[i]
        local x   = i * w + (i - 1) * spacing
        local y   = (WaveY(i, vwave) + WaveY(i + 1, vwave)) / 2
        div:ClearAllPoints(); div:SetPoint("LEFT", frame, "LEFT", x, y); div:SetSize(1, h); div:Show()
      end
    else
      for i = 1, NUM_ICONS - 1 do frame.segDiv[i]:Hide() end
    end
  else
    local size = tonumber(active.iconSize) or 30
    frame:SetSize((size * NUM_ICONS) + (spacing * (NUM_ICONS - 1)), size)

    for i = 1, NUM_ICONS do
      local pip   = frame.pips[i]
      local btn   = frame.buttons[i]
      local iconC = frame.iconsCustom[i]
      local iconD = frame.iconsDefault[i]

      pip:SetSize(size, size); pip:ClearAllPoints()
      if i == 1 then
        pip:SetPoint("LEFT", frame, "LEFT", 0, WaveY(i, vwave))
      else
        pip:SetPoint("LEFT", frame.pips[i - 1], "RIGHT", spacing, WaveY(i, vwave) - WaveY(i - 1, vwave))
      end

      btn:ClearAllPoints();   btn:SetAllPoints(pip); btn:SetFrameLevel(pip:GetFrameLevel() + 10)
      iconC:ClearAllPoints(); iconC:SetAllPoints(btn)
      iconD:ClearAllPoints(); iconD:SetAllPoints(pip)
    end
  end

  if style == "custom" then Masque_ReskinSafe() end

  local zoom = active.zoom or 0
  if style == "custom" then
    for i = 1, NUM_ICONS do ApplyZoom(frame.iconsCustom[i], zoom); ResetTex(frame.iconsDefault[i]) end
  else
    for i = 1, NUM_ICONS do ApplyZoom(frame.iconsDefault[i], zoom); ResetTex(frame.iconsCustom[i]) end
  end
end

-- ============================== Update ==============================
function PHP.UpdateHPTracker()
  local conf = S()
  if not conf or conf.enabled == false then return end

  local active = ActiveHP(conf)
  local frame  = PHP.EnsureHPBarFrame()

  frame:ClearAllPoints()
  frame:SetPoint("CENTER", UIParent, "CENTER", tonumber(conf.x) or 0, tonumber(conf.y) or -215)
  frame:SetAlpha(tonumber(active.alpha) or 1)

  ApplyStyle(frame, conf, active)
  LayoutBar(frame, active, conf.style)

  local custom  = (conf.style == "custom")
  local isBar   = (conf.style == "custom_bar")
  local hp      = GetHP()
  local preview = IsPreview()

  -- Colors
  local cfgFill  = active.fillColor  or conf.fillColor
  local cfgEmpty = active.emptyColor or conf.emptyColor
  local fillI    = (type(cfgFill)  == "table" and { cfgFill[1]  or 1,  cfgFill[2]  or 1,  cfgFill[3]  or 1  }) or { 1, 1, 1 }
  local emptyI   = (type(cfgEmpty) == "table" and { cfgEmpty[1] or .3, cfgEmpty[2] or .3, cfgEmpty[3] or .3 }) or { .3, .3, .3 }
  local isWhite  = (type(cfgFill) == "table" and cfgFill[1] == 1 and cfgFill[2] == 1 and cfgFill[3] == 1)
  local fillB    = (type(cfgFill) == "table" and not isWhite) and { cfgFill[1], cfgFill[2], cfgFill[3] } or { 228/255, 211/255, 127/255 }
  local emptyB   = emptyI

  local texPath  = isBar and FetchStatusbarTexture(active.barTexture or conf.barTexture) or nil
  local spacing  = tonumber(active.iconSpacing) or 0

  -- Icons
  if not isBar then
    for i = 1, NUM_ICONS do
      frame.buttons[i]:SetShown(custom)
      frame.iconsCustom[i]:SetShown(custom)
      frame.iconsDefault[i]:SetShown(not custom)

      local filled = preview or (i <= hp)
      if custom then
        frame.iconsCustom[i]:SetVertexColor(filled and fillI[1] or emptyI[1], filled and fillI[2] or emptyI[2], filled and fillI[3] or emptyI[3])
      else
        frame.iconsDefault[i]:SetVertexColor(filled and fillI[1] or emptyI[1], filled and fillI[2] or emptyI[2], filled and fillI[3] or emptyI[3])
      end
    end
  else
    for i = 1, NUM_ICONS do
      frame.buttons[i]:Hide()
      frame.iconsCustom[i]:Hide()
      frame.iconsDefault[i]:Hide()
    end
  end

  -- Segmented bar
  if isBar then
    local w = tonumber(active.width) or 40
    local h = tonumber(active.height) or 20
    local totalW = (w * NUM_ICONS) + (spacing * (NUM_ICONS - 1))

    for i = 1, NUM_ICONS do
      local filled = preview or (i <= hp)
      local bg, fill = frame.segBG[i], frame.segFill[i]
      bg:Show(); fill:Show()
      bg:SetColorTexture(0.1, 0.1, 0.1, 0.8)

      if texPath then
        local left, right = (i - 1) * (w + spacing), (i - 1) * (w + spacing) + w
        local u1 = (totalW > 0) and (left  / totalW) or 0
        local u2 = (totalW > 0) and (right / totalW) or 1
        fill:SetTexture(texPath)
        fill:SetTexCoord(u1, u2, 0, 1)
        fill:SetVertexColor(filled and fillB[1] or emptyB[1],
                            filled and fillB[2] or emptyB[2],
                            filled and fillB[3] or emptyB[3], 1)
      else
        fill:SetTexture(nil)
        fill:SetTexCoord(0, 1, 0, 1)
        if filled then
          fill:SetColorTexture(fillB[1], fillB[2], fillB[3], 1)
        else
          fill:SetColorTexture(emptyB[1], emptyB[2], emptyB[3], 1)
        end
      end
    end
    for i = 1, NUM_ICONS - 1 do
      if spacing <= 0 then frame.segDiv[i]:Show() else frame.segDiv[i]:Hide() end
    end
  else
    for i = 1, NUM_ICONS do frame.segBG[i]:Hide(); frame.segFill[i]:Hide() end
    for i = 1, NUM_ICONS - 1 do frame.segDiv[i]:Hide() end
  end

  -- Pulse
  local pulseOn      = (ActiveHP(conf).pulseAnim ~= false)
  local styleChanged = (frame._lastStyle ~= conf.style)
  if styleChanged then frame._lastHP = hp; frame._lastStyle = conf.style end
  if pulseOn then
    local last = tonumber(frame._lastHP or hp) or 0
    if hp > last then
      for i = last + 1, math.min(hp, NUM_ICONS) do
        if isBar then       PlayPulse(frame.segFill[i])
        elseif custom then  PlayPulse(frame.buttons[i])
        else                PlayPulse(frame.pips[i]) end
      end
    end
  end
  frame._lastHP, frame._lastStyle = hp, conf.style

  -- Custom icon model FX
  local FX = (conf.style == "custom") and PHP.ModelAnimations
  if FX then
    local M = PHP.ModelAnimations
    if not M.created then
      frame.icons = frame.iconsCustom
      M.CreateModelAnimations(frame, NUM_ICONS)
    else
      frame.icons = frame.iconsCustom
    end
    M.SetAlpha(tonumber(active.alpha) or 1)

    -- Show models by current HP when not in preview
    if preview then
      M.SetAlwaysVisible(true)
      M.UpdateLayout(frame, nil)
      M.UpdateVisibility(NUM_ICONS, NUM_ICONS)   -- all visible in preview
    else
      M.SetAlwaysVisible(false)
      M.UpdateLayout(frame, nil)
      local visible = math.min(hp or 0, NUM_ICONS)
      M.UpdateVisibility(NUM_ICONS, visible)     -- visible equals current HP
    end
  elseif PHP.ModelAnimations then
    PHP.ModelAnimations.HideAllModelAnimations()
  end
end

-- ============================ Public API ============================
local hpBarVisible = false

function PHP.EnableHPBarFrame()
  if hpBarVisible then return end
  local conf = S()
  if conf and conf.enabled == false then return end

  local frame = PHP.EnsureHPBarFrame()
  if not frame._masqueInit and MS then
    Masque_EnableSafe(frame.buttons, frame.iconsCustom)
    frame._masqueInit = true
  end

  frame:Show()
  for i = 1, NUM_ICONS do frame.pips[i]:Show() end
  hpBarVisible = true
  PHP.UpdateHPTracker()
end

function PHP.DisableHPBarFrame()
  if not hpBarVisible then return end
  local frame = PHP.EnsureHPBarFrame()
  frame:Hide()
  if PHP.ModelAnimations then PHP.ModelAnimations.HideAllModelAnimations() end
  hpBarVisible = false
end