local TXUI, F, E, I, V, P, G = unpack((select(2, ...)))
local CM = TXUI:NewModule("CooldownManager", "AceHook-3.0")

local _G = _G

CM.frameNames = {
  essential = "EssentialCooldownViewer",
  utility = "UtilityCooldownViewer",
  buff = "BuffIconCooldownViewer",
  buffBar = "BuffBarCooldownViewer",
}

function CM:OnEditModeEnter()
  self:RestoreOriginalParents()
  self:RestoreAnchors()
  self:DisableDynamicWidthForEditMode()
end

function CM:OnEditModeExit()
  self:OnCooldownManagerChanged()
  self:EnableDynamicWidthAfterEditMode()
end

function CM:OnCooldownManagerChanged()
  self:SetAnchors()
  self:SetParent()
  self:CenterAllViewers()
end

function CM:Disable()
  if not self.Initialized then return end

  self:UnhookAll()
  self:DisableBarOverrides()
  self:DisableCentering()
  self:DisableFading()
  self:DisableDynamicWidth()
  self:DisableAnchoring()
  self:DisableKeybinds()

  F.Event.UnregisterFrameEventAndCallback("PLAYER_ENTERING_WORLD", self)
  F.Event.UnregisterFrameEventAndCallback("ZONE_CHANGED_NEW_AREA", self)

  if _G.EventRegistry then
    _G.EventRegistry:UnregisterCallback("CooldownViewerSettings.OnDataChanged", self)
    _G.EventRegistry:UnregisterCallback("EditMode.Enter", self)
    _G.EventRegistry:UnregisterCallback("EditMode.Exit", self)
  end
end

function CM:DatabaseUpdate()
  -- Set db
  self.db = F.GetDBFromPath("TXUI.addons.cooldownManager")

  F.Event.ContinueOutOfCombat(function()
    -- Disable only out of combat
    self:Disable()

    -- Check requirements
    if not TXUI:HasRequirements(I.Requirements.CooldownManager) then return end
    if not self.db then return end
    if not self.db.enabled then return end

    E:SetCVar("cooldownViewerEnabled", "1")

    -- Apply bar overrides first (may affect what bars are available for anchoring)
    local hasClassBarOverride = self.db.classBarOverride and self.db.classBarOverride.enabled
    local hasPowerBarOverride = self.db.powerBarOverride and self.db.powerBarOverride.enabled
    if hasClassBarOverride or hasPowerBarOverride then self:EnableBarOverrides() end

    -- Enable fading if enabled
    if self.db.fading then self:EnableFadingAfterUnitsLoaded() end

    -- Enable dynamic width features if enabled
    local dw = self.db.dynamicWidth
    if dw and dw.enabled then
      if dw.powerClassBars then self:EnableDynamicBarsWidth() end
      if dw.castBar then self:EnableDynamicCastbarWidth() end
    end

    -- Enable anchoring if any anchor is enabled
    if self.db.anchors then
      local a = self.db.anchors
      if a.essential.enabled or a.utility.enabled or a.buff.enabled or a.buffBar.enabled then self:EnableAnchoring() end
    end

    -- Enable centering if any viewer has it enabled
    if self.db.centering then
      local c = self.db.centering
      if c.essential or c.utility or c.buff or c.buffBar then self:EnableCentering() end
    end

    -- Enable keybind overlays if any viewer has keybinds enabled
    if self.db.keybinds then
      local kb = self.db.keybinds
      if (kb.essential and kb.essential.enabled) or (kb.utility and kb.utility.enabled) then self:EnableKeybinds() end
    end

    -- Re-apply all features on settings change or edit mode exit since they reset frames
    if _G.EventRegistry then
      _G.EventRegistry:RegisterCallback("CooldownViewerSettings.OnDataChanged", self.OnCooldownManagerChanged, self)
      _G.EventRegistry:RegisterCallback("EditMode.Enter", self.OnEditModeEnter, self)
      _G.EventRegistry:RegisterCallback("EditMode.Exit", self.OnEditModeExit, self)
    end
  end)
end

function CM:Initialize()
  -- Don't init second time
  if self.Initialized then return end

  self.essentialViewer = _G[self.frameNames.essential]

  -- Register for updates
  F.Event.RegisterOnceCallback("TXUI.InitializedSafe", F.Event.GenerateClosure(self.DatabaseUpdate, self))
  F.Event.RegisterCallback("TXUI.DatabaseUpdate", self.DatabaseUpdate, self)
  F.Event.RegisterCallback("CooldownManager.DatabaseUpdate", self.DatabaseUpdate, self)

  -- We are done, hooray!
  self.Initialized = true
end

if TXUI.IsRetail then TXUI:RegisterModule(CM:GetName()) end
