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 k,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)
  local dual = secondaryUnitId and self.mode.fillColor[2]
  
  if dual then
    self.font1:SetFont (ss.private.font.sphere, ss.private.fontSize.sphereSmall, ss.private.fontFlag.sphere)
    self.font1:SetPoint("CENTER", -20, 5)
    self.font2:SetFont (ss.private.font.sphere, ss.private.fontSize.sphereSmall, ss.private.fontFlag.sphere)
    self.font2:SetPoint("CENTER", 20, 5)
  else
    self.font1:SetFont (ss.private.font.sphere, ss.private.fontSize.sphereLarge, ss.private.fontFlag.sphere)
    self.font1:SetPoint("CENTER", 0, 15)
    self.font2:SetFont (ss.private.font.sphere, ss.private.fontSize.sphereMedium, ss.private.fontFlag.sphere)
    self.font2:SetPoint("CENTER", 0, -5)
  end
end

function SeamoreSpheresContainer:SetResource(configName)
  return self:GetParent():SetResource(configName)
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(self)
    if self.ResourceUpdate then
      self:ResourceUpdate()
    end
  end)
end)
