local MicroSphereContainer = {}
local AddOnName, nsVars = ...
local ss = nsVars.SS

local math = math

--- Updates a fill texture and it's gradient data.
-- @param self A reference to the fill texture.
-- @param targetHeight The target height
-- @param color The target color.
-- @param maxAlpha The alpha limit.
--
local function updateGradientFilling(self, targetHeight, color, maxAlpha)
  if self and ss.global.show.gradient then
    if color and maxAlpha and self.gradient then
      local r, g, b = ss.Utils:GetRGBAValues(color)
      self.gradient:SetGradientAlpha("VERTICAL", r, g, b, maxAlpha, r, g, b, 0)
    end

    self._gradT = targetHeight / self._maxH
    self._gradT = self._gradT > 1 and 1 or self._gradT -- ensure value isnt greater than 1 when resource changes

    local textCoordTop = (self._gradT - ss.gradientScale)
    local newHeight = targetHeight - (self._maxH * ss.gradientScale)
    textCoordTop = textCoordTop < 0 and 0 or textCoordTop

    if self._gradT < 0 then
      self._gradT = 0
    end

    newHeight = newHeight < 1 and 1 or newHeight

    self:SetHeight(newHeight)
    self:SetTexCoord(0, 1, math.abs(textCoordTop - 1), 1)

    self._gradB = 1 - (self._gradT - ss.gradientScale)
    self._gradH = self._maxH * ss.gradientScale

    self._gradB = self._gradB < 0 and 0 or self._gradB
    self._gradB = self._gradB > 1 and 1 or self._gradB

    self._newY = (self._maxH * (1 - self._gradB)) - self._gradH

    if self._updateSplitValues then
      self:_updateSplitValues(textCoordTop, newHeight)
    end
  end
end

--- Updates a texture gradient.
-- @param self The texture reference.
--
local function updateGradient(self)
  if self and ss.global.show.gradient then
    self.gradient:SetHeight(self._gradH)
    self.gradient:SetTexCoord(0, 1, math.abs(self._gradT - 1), math.abs(self._gradB))
    self.gradient:SetPoint("BOTTOM", self._newX, self._newY)

    -- Clear temp values.
    self._maxH = nil
    self._newY = nil
    self._newX = nil
    self._gradH = nil
    self._gradT = nil
    self._gradB = nil
  end
end

local function setAlpha(self, a)
  self:_SetAlpha(a <= 0 and 0 or 1)
end

local function setGradientAlpha(self, d, r1, g1, b1, a1, r2, g2, b2, a2)
  a1 = (a1 <= 0) and 0 or 1
  self:_SetGradientAlpha(d, r1, g1, b1, a1, r2, g2, b2, a2)
end

local function setTexture(self, ...)
  self.SetAlpha = ss.global.general.fadeMicroSpheres and self._SetAlpha or setAlpha
  self.gradient.SetGradientAlpha = ss.global.general.fadeMicroSpheres and self.gradient._SetGradientAlpha or setGradientAlpha
  self:_SetTexture(...)
end

local function initTextures(container)
  container.filling._SetAlpha = container.filling.SetAlpha
  container.filling._SetTexture = container.filling.SetTexture
  container.filling.SetAlpha = ss.global.general.fadeMicroSpheres and container.filling._SetAlpha or setAlpha
  container.filling.SetTexture = setTexture
  container.filling.gradient._SetGradientAlpha = container.filling.gradient.SetGradientAlpha
  container.filling.gradient.SetGradientAlpha = setGradientAlpha
  container.filling.gradient.SetGradientAlpha = ss.global.general.fadeMicroSpheres and container.filling.gradient._SetGradientAlpha or setGradientAlpha
  container.filling._updateValues = updateGradientFilling
  container.filling._updateGradient = updateGradient

  function container.filling:UpdateGradient(targetHeight, maxHeight, color, maxAlpha)
    self._maxH = maxHeight
    self._newX = 0
    self:_updateValues(targetHeight, color, maxAlpha)
    self:_updateGradient()
  end
end

local function setTextures(container, color, fillIndex)
  -- Set textures
  local texture = ss.FillTextures.get(ss.profile.microResourceFillTextureGroups[fillIndex], ss.profile.microResourceFillTextures[fillIndex])

  if texture[2] then
    texture = ss.FillTextures.defaultTexture
  end

  container.filling:SetTexture(texture)
  container.filling:SetAlpha(1)
  container.filling:SetVertColor(color)

  if ss.global.show.gradient then
    -- Set gradient color.
    local r, g, b = container.filling:GetVertexColor()
    container.fillingGradient:SetTexture(texture)
    container.fillingGradient:SetAlpha(1)
    container.fillingGradient:SetGradientAlpha("VERTICAL", r, g, b, 0, r, g, b, 0)
  else
    container.fillingGradient:SetAlpha(0)
    container.fillingGradient:SetGradientAlpha("VERTICAL", 0, 0, 0, 0, 0, 0, 0, 0)
  end
end

local function initAnimation(container)
  local size = container:GetWidth() * 2.172
  container.animation:SetSize(size, size)
end

function MicroSphereContainer:GetTooltipLabel()
  return self.tooltipLabel
end

function MicroSphereContainer:Init(resource, fillIndex)
  self:SetScale(1)
  self:SetHeight(30 / ss.db[self:GetParent().configName].general.scale)
  self:SetWidth(30 / ss.db[self:GetParent().configName].general.scale)
  self:SetAllPoints(self:GetParent())
  self:SetFrameStrata(self:GetParent():GetFrameStrata() or "HIGH")
  self.displayMode = "preview"

  initTextures(self)
  setTextures(self, resource[2], fillIndex)

  initAnimation(self)
  self:Show()

  self.resourceAnimation:Init()
end

rawset(_G, "MicroSphereContainer_OnLoad", function(self)
  ss.Extensions:DelegateVertexColor(
      self.filling,
      self.fillingGradient)

  self.filling.gradient = self.fillingGradient

  for k, v in pairs(MicroSphereContainer) do
    self[k] = v
  end
end)
