local SeamoreSpheresContainer = {}
local AddOnName, nsVars = ...
local ss = nsVars.SS
local CreateFrame = ss.CreateFrame

local pairs = pairs

--- Updates a micro sphere display.
-- @param display The parent display.
-- @param group The resource group.
-- @see updateResourceGroupStagger().
-- @see updateResourceGroupBuff().
-- @see updateResourceGroupDefault().
--
local function updateResourceGroup(display, group)
  group = group or "resource"

  -- TODO: Should find a way to end early if no change is needed.
  if display[group .. "GroupUnitId"] then
    local _, curRes, maxRes, start, duration

    if display[group .. "GroupUnitId"] ~= "buff" then
      _, curRes, maxRes, start, duration = display[group .. "GroupUnit"].getMinMax(display[group .. "GroupUnitId"])
    end

    for _, v in pairs(display[group .. "Group"]) do
      v:GetParent():UpdateResource(display[group .. "GroupUnit"], curRes, maxRes, start, duration)
    end
  end
end

local function initFonts(container)
  container:SetFonts()
  container.font1:SetTextColor(ss.Utils:GetRGBAValues(container.mode.fontColor[1]))
  container.font2:SetTextColor(ss.Utils:GetRGBAValues(container.mode.fontColor[2]))

  if ss.db[container.configName].font[1].show then
    container.font1:Show()
  else
    container.font1:Hide()
  end

  if ss.db[container.configName].font[2].show then
    container.font2:Show()
  else
    container.font2:Hide()
  end
end

local function setSwirlGroup(container, size, swirlTextures)
  container.swirl1:UpdateSwirl(swirlTextures[1], size * 0.9, container.mode.swirlColor[1])
  container.swirl1:SetSpeed(container.swirlConfig.speed, 2, 4)
  container.swirl2:UpdateSwirl(swirlTextures[2], size * 0.9, container.mode.swirlColor[2] or container.mode.swirlColor[1])
  container.swirl2:SetSpeed(container.swirlConfig.speed, 3, 5)
  container.swirl3:UpdateSwirl(swirlTextures[3], size * 0.9, container.mode.swirlColor[3] or container.mode.swirlColor[1])
  container.swirl3:SetSpeed(container.swirlConfig.speed, 2, 3)
end

local function initSwirlGroup(container, size, swirlTextures)
  -- Initialize the swirl textures.
  container.swirl1:Init(swirlTextures[1], size * 0.9, container.mode.swirlColor[1])
  container.swirl1:SetSpeed(container.swirlConfig.speed, 2, 4)
  container.swirl2:Init(swirlTextures[2], size * 0.9, container.mode.swirlColor[2] or container.mode.swirlColor[1])
  container.swirl2:SetSpeed(container.swirlConfig.speed, 3, 5)
  container.swirl3:Init(swirlTextures[3], size * 0.9, container.mode.swirlColor[3] or container.mode.swirlColor[1])
  container.swirl3:SetSpeed(container.swirlConfig.speed, 2, 3)
end

local function UpdateMicroSpheres(container, group)
  if group then
    updateResourceGroup(container, group)
  else
    updateResourceGroup(container, "resource")
    updateResourceGroup(container, "secondaryResource")
  end
end

function SeamoreSpheresContainer:Init()
  local configName = self:GetParent().configName
  local displayMode = self:GetParent().displayMode

  self:SetScale(1)
  self:SetHeight(ss.global.general.SphereSize / ss.db[configName].general.scale)
  self:SetWidth(ss.global.general.SphereSize / ss.db[configName].general.scale)

  if displayMode == "active" then
    self:SetFrameStrata("MEDIUM")
    self.UpdateMicroSpheres = UpdateMicroSpheres
  else
    self:SetFrameStrata("HIGH")
    self.UpdateMicroSpheres = nil
    self.displayMode = "preview"
  end

  -- Initialize properties.
  self.textFormat = ss.db[configName].textFormat
  self.displayMode = displayMode
  self.configName = configName
  self.mode = ss.db[configName].modes[ss.profile.modeInfo[configName].modeSpec][ss.profile.modeInfo[configName].mode]
  self.swirlConfig = self.mode.swirl
  self.swirlId = self.swirlConfig.id

  -- Initialize fill textures.
  self.layers:Init()

  -- Initialize swirls.
  local size = (self.displayMode == "active") and ss.db[self.configName].general.size
      or (ss.db[self.configName].general.size * ss.db[self.configName].general.scale)

  initSwirlGroup(self, ss.FillTextures.getSwirlSize(self.swirlConfig.id, size), ss.FillTextures.get(self.swirlConfig.groupId, self.swirlConfig.id))

  -- Initialize the animation.
  self.animation:Init(ss.db[self.configName].animation)

  self:SetMode()
  self:Show()

  self.ResourceUpdate = self.displayMode == "active" and (self.ResourceUpdate or self.resourceMonitor:Watch()) or nil
end

--- Creates the micro sphere frames.
-- @param index The position to create.
-- @param resource The resource data.
-- @param region The sphere region.
-- @return The configured sphere.
--
function SeamoreSpheresContainer:InitMicroSphere(index, resource, region, group)
  local name = ss._f .. self.configName .. "_" .. "SeamoreSpheresMicroSphere" .. index
  local base = CreateFrame("Button", name, self, "SeamoreSpheresMicroSphereTemplate")
  base:Init(self.configName, index, resource, region, group)

  return base.sphere
end

function SeamoreSpheresContainer:SetMode(mode, modeName)
  self.modeName = modeName
  self.mode = mode or self.mode
  self.swirlConfig = self.mode.swirl
  self.swirlId = self.swirlConfig.id

  -- Initialize fill textures.
  self.layers:Refresh()

  -- Initialize swirls.
  local size = (self.displayMode == "active") and ss.db[self.configName].general.size
      or (ss.db[self.configName].general.size * ss.db[self.configName].general.scale)

  setSwirlGroup(self, ss.FillTextures.getSwirlSize(self.swirlConfig.id, size), ss.FillTextures.get(self.swirlConfig.groupId, self.swirlConfig.id))

  -- Initialize the animation.
  self.animation:SetAnimation(ss.db[self.configName].animation)

  if self.displayMode == "preview" then
    self.animation:SetFrameLevel(ss.db[self.configName].animation.frameLevel + ss.private.layout.config.frameLevelAdjust)
  end

  -- Initialize fonts.
  initFonts(self)

  return self.config
end

function SeamoreSpheresContainer:SetFonts()
  local _, secondaryUnitId = ss.ClassResources.modeResourceUnitId(self.configName,
      (self.displayMode == "preview") and self.modeName)
  local dual = secondaryUnitId and self.mode.fillColor[2]

  if dual then
    self.font1:SetFontObject(ss.FontObjects.Exo2Medium14)
    self.font1:SetPoint("CENTER", -20, 5)
    self.font2:SetFontObject(ss.FontObjects.Exo2Medium14)
    self.font2:SetPoint("CENTER", 20, 5)
  else
    self.font1:SetFontObject(ss.FontObjects.Exo2Medium28)
    self.font1:SetPoint("CENTER", 0, 15)
    self.font2:SetFontObject(ss.FontObjects.Exo2Medium16)
    self.font2:SetPoint("CENTER", 0, -5)
  end
end

rawset(_G, "SeamoreSpheresContainer_OnLoad", function(self)
  for k, v in pairs(SeamoreSpheresContainer) do
    self[k] = v
  end

  self.resourceMonitor = self.resourceMonitor or ss.ResourceMonitor:New()
  self:HookScript("OnUpdate", function()
    if self.ResourceUpdate then
      self:ResourceUpdate()
    end
  end)
end)
