--[[Created by Slothpala]]--
local _, addonTable = ...
local addon = addonTable.addon

local module = addon:NewModule("DefensiveOverlay")

--------------------
--- Libs & Utils ---
--------------------

local Media = LibStub("LibSharedMedia-3.0")
local CR = addonTable.CallbackRegistry
local LGIST = LibStub:GetLibrary("LibGroupInSpecT-1.1")

local special_auras = {
  -- Lichborne
  [49039] = function(unit)
    local guid = UnitGUID(unit)
    local unit_info = guid and LGIST:GetCachedInfo(guid)
    return unit_info and unit_info.talents and unit_info.talents[96187] or false -- Unholy Endurance
  end,
  -- Fade
  [586] = function(unit)
    local guid = UnitGUID(unit)
    local unit_info = guid and LGIST:GetCachedInfo(guid)
    return unit_info and unit_info.talents and unit_info.talents[103835] or false -- Translucent Image
  end,
  -- Defensive Stance
  -- I think this is only of interest if the unit is a DAMAGER.
  [386208] = function(unit)
    local role = UnitGroupRolesAssigned(unit) or ""
    return role == "DAMAGER"
  end,
  -- Bear Form
  -- Same as defensive stance this is only a useful information on non tanks.
  [5487] = function(unit)
    local role = UnitGroupRolesAssigned(unit) or ""
    return role == "DAMAGER"
  end
  --[[
    find talent id fast
    for k,v in pairs(unit_info.talents) do
      for i, x in pairs(v) do
        if x == "Talent Name" then
          print(k)
        end
      end
    end
  ]]
}

local callback_id
function module:OnEnable()
  -- Get the database objects
  local db_obj = CopyTable(addon.db.profile.DefensiveOverlay)
  local db_obj_font_duration = CopyTable(addon.db.profile.DefensiveOverlayDurationFont)
  local db_obj_font_stack = CopyTable(addon.db.profile.DefensiveOverlayStackFont)
  -- Fetch DB values
  local path_to_duration_font = Media:Fetch("font", db_obj_font_duration.font)
  local path_to_stack_font = Media:Fetch("font", db_obj_font_stack.font)

  -- AuraFrame options
  local aura_frame_options = {
    -- Position
    anchor_point = db_obj.point,
    relative_point = db_obj.relative_point,
    offset_x = db_obj.offset_x,
    offset_y = db_obj.offset_y,
    -- Num indicators row*column
    num_indicators_per_row = db_obj.num_indicators_per_row,
    num_indicators_per_column = db_obj.num_indicators_per_column,
    -- Orientation
    direction_of_growth_vertical = db_obj.direction_of_growth_vertical,
    vertical_padding = db_obj.vertical_padding,
    direction_of_growth_horizontal = db_obj.direction_of_growth_horizontal,
    horizontal_padding = db_obj.horizontal_padding,
    -- Indicator size
    indicator_width = db_obj.indicator_width,
    indicator_height = db_obj.indicator_height,
    -- Indicator border
    indicator_border_thickness = db_obj.indicator_border_thickness,
    indicator_border_color = db_obj.indicator_border_color,
    -- Font: Duration
    path_to_duration_font = path_to_duration_font,
    duration_font_size = db_obj_font_duration.font_size,
    duration_font_outlinemode = db_obj_font_duration.font_outlinemode,
    duration_font_color = db_obj_font_duration.text_color,
    duration_font_point = db_obj_font_duration.point,
    duration_font_relative_point = db_obj_font_duration.relative_point,
    duration_font_offset_x = db_obj_font_duration.offset_x,
    duration_font_offset_y = db_obj_font_duration.offset_y,
    duration_font_shadow_color =  db_obj_font_duration.shadow_color,
    duration_font_shadow_offset_x = db_obj_font_duration.shadow_offset_x,
    duration_font_shadow_offset_y = db_obj_font_duration.shadow_offset_y,
    duration_font_horizontal_justification = db_obj_font_duration.horizontal_justification,
    duration_font_vertical_justification = db_obj_font_duration.vertical_justification,
    -- Font: Stack
    path_to_stack_font = path_to_stack_font,
    stack_font_size = db_obj_font_stack.font_size,
    stack_font_outlinemode = db_obj_font_stack.font_outlinemode,
    stack_font_color = db_obj_font_stack.text_color,
    stack_font_point = db_obj_font_stack.point,
    stack_font_relative_point = db_obj_font_stack.relative_point,
    stack_font_offset_x = db_obj_font_stack.offset_x,
    stack_font_offset_y = db_obj_font_stack.offset_y,
    stack_font_shadow_color =  db_obj_font_stack.shadow_color,
    stack_font_shadow_offset_x = db_obj_font_stack.shadow_offset_x,
    stack_font_shadow_offset_y = db_obj_font_stack.shadow_offset_y,
    stack_font_horizontal_justification = db_obj_font_stack.horizontal_justification,
    stack_font_vertical_justification = db_obj_font_stack.vertical_justification,
    -- Cooldown
    show_swipe = db_obj.show_swipe,
    reverse_swipe = db_obj.reverse_swipe,
    show_edge = db_obj.show_edge,
    show_cooldown_numbers = db_obj.show_cooldown_numbers,
    -- Tooltip
    show_tooltip = db_obj.show_tooltip,
  }

  -- Create a callback to create an aura frame when a new frame env is created.
  local function create_or_update_defensive_overlay(cuf_frame)
    if not cuf_frame.RFS_FrameEnvironment.aura_frames["DefensiveOverlay"] then
      cuf_frame.RFS_FrameEnvironment.aura_frames["DefensiveOverlay"] = addon:NewAuraFrame(cuf_frame)
    end
    cuf_frame.RFS_FrameEnvironment.aura_frames["DefensiveOverlay"]:Enable(aura_frame_options)
    cuf_frame.RFS_FrameEnvironment.aura_frames["DefensiveOverlay"].Update = function(self, aura_table)
      local indicator_pos = 1
      aura_table:Iterate(function(auraInstanceID, aura)
        if indicator_pos > self.num_indicators then
          return true
        end

        -- Some auras are only a defensive if a talent that improves it is learned.
        local is_special_aura = special_auras[aura.spellId] and special_auras[aura.spellId](cuf_frame.unit)
        if is_special_aura == false then
          return false
        end
        -- else(nil or true) continue

        self.indicators[indicator_pos]:SetAura(aura)

        if self.on_set_aura_callback then
          self.on_set_aura_callback(self.indicators[indicator_pos], aura)
        end
        indicator_pos = indicator_pos + 1

        return false
      end)

      for i=indicator_pos, self.num_indicators do
        self.indicators[i]:Clear()
      end
    end
  end
  -- Place the callback in the callback table.
  addonTable.on_create_frame_env_callbacks["DefensiveOverlay"] = create_or_update_defensive_overlay

  -- Handle Aura Changes
  local function on_auras_changed(cuf_frame)
    cuf_frame.RFS_FrameEnvironment.aura_frames["DefensiveOverlay"]:Update(cuf_frame.RFS_FrameEnvironment.grouped_auras["DefensiveOverlay"])
  end

  -- Gather all wanted spellIds
  local tracked_auras = {}
  local prio_list = {}
  local class_cooldowns = addon:ClassCooldowns_GetDB()
  for class, info in next, class_cooldowns do
    for spell, spell_info in next, info.defensive do
      local db_spell_info = db_obj.auras[spell]
      if db_spell_info.track then
        for _, spell_id in next, spell_info.auras do
          tracked_auras[spell_id] = true
          prio_list[spell_id] = db_spell_info.prio or spell_info.prio or 1
          --print(tostring(spell_id) .. " has prio of: " .. tostring(prio_list[spell_id]))
        end
      end
    end
  end

  -- Update the whitelist.
  addon:UpdateWhitelist()

  -- Comparator function to handle aura priority sorting
  local function aura_comparator(aura_a, aura_b)
    --print("aura_a has the spell_id: " .. tostring(aura_a.spellId) .. " || aura_b has the spell_id: " .. tostring(aura_b.spellId))
    --print("aura_a has the prio: " .. tostring(prio_list[aura_a.spellId]) .. " || aura_b has the prio: " .. tostring(prio_list[aura_b.spellId]))
    return prio_list[aura_a.spellId] < prio_list[aura_b.spellId]
  end

  -- Register the defensive spell ids for DefensiveOverlay. The cuf_frames frame env will use this name as the update notifier event.
  addon:RegisterAuraGroup("DefensiveOverlay", tracked_auras, aura_comparator)

  -- Register the DefensiveOverlay callback
  callback_id = CR:RegisterCallback("DefensiveOverlay", on_auras_changed)

  addon:IterateRoster(function(cuf_frame)
    create_or_update_defensive_overlay(cuf_frame)
    if cuf_frame.unit and cuf_frame:IsShown() then
      addon:CreateOrUpdateAuraScanner(cuf_frame)
    end
  end, true)
end

function module:OnDisable()
  -- Update the whitelist.
  addon:UpdateWhitelist()
  -- Remove the callback in the callback table.
  addonTable.on_create_frame_env_callbacks["DefensiveOverlay"] = nil
  -- Unregister the callback
  CR:UnregisterCallback("DefensiveOverlay", callback_id)
  addon:UnregisterAuraGroup("DefensiveOverlay")
  -- Apply the changes to all frames currently displayed.
  local function hide_overlay(cuf_frame)
    cuf_frame.RFS_FrameEnvironment.aura_frames["DefensiveOverlay"]:Disable()
    if cuf_frame.unit and cuf_frame:IsShown() then
      addon:CreateOrUpdateAuraScanner(cuf_frame)
    end
  end
  addon:IterateRoster(hide_overlay, true)
end


