--- Buff Information for Micro Spheres
--
local DebuffData = {}
local AddOnName, nsVars = ...
local ss = nsVars.SS

local GetTime, FindAuraByName = GetTime, AuraUtil.FindAuraByName
local string, tonumber, strlower, select = string, tonumber, strlower, select

--- Provides debuff information.
--- @param buff number The buff identifier.
--- @return string, number, number, number, number The current progression values.
--- @see FindAuraByName().
local function getMinMax(buff)
  local duration, expires = select(5, FindAuraByName(buff, "target", "PLAYER HARMFUL"))
  return buff, (duration and 1 or 0), 1, (duration or 1), (expires or 1)
end

--- Provides corruption information.
--- @param buff number The buff identifier.
--- @return string, number, number, number, number The current progression values.
--- @see FindAuraByName().
local function getCorruption(buff)
  local duration, expires = select(5, FindAuraByName(buff, "target", "PLAYER HARMFUL"))
  -- Values are 0 if corruption is permanent, return time + 1 if so.
  return buff, (duration and 1 or 0), 1, (duration or 1), (expires and (expires == 0 and (GetTime() + 1) or expires) or 1)
end

--- Provides stacking debuff information.
--- @param spell number The spell identifier.
--- @return string, number, number, number, number The current progression values.
--- @see FindAuraByName().
local function getStackingMinMax(spell)
  local buffName = string.gsub(spell, "%d", "")
  local index = strlower(string.gsub(spell, "[ :'%(%)%d]", ""))

  local stacks, _, duration, expires = select(3, FindAuraByName(buffName, "target", "PLAYER HARMFUL"))

  if stacks then
    if stacks == 0 then
      stacks = 1
    end

    local buffStack = string.gsub(spell, "[^%d]", "")
    buffStack = (buffStack and buffStack ~= "") and tonumber(buffStack) or 1

    duration = (stacks >= buffStack) and duration or nil
    expires = (stacks >= buffStack) and expires or nil
  end

  return index, (duration and 1 or 0), 1, (duration or 1), (expires or 1)
end

DebuffData.demonhunter = {
  ["fierybrand"] = {
    "Fiery Brand",
    { r = 181, g = 233, b = 18, a = 1 },
    getMinMax = getMinMax,
    name = "Fiery Brand",
  },
}

DebuffData.warlock = {
  ["corruption"] = {
    "Corruption",
    { r = 152, g = 24, b = 32, a = 1 },
    getMinMax = getCorruption,
    name = "Corruption",
  },
  ["agony"] = {
    "Agony",
    { r = 187, g = 69, b = 32, a = 1 },
    getMinMax = getMinMax,
    name = "Agony",
  },
  ["unstableaffliction"] = {
    "Unstable Affliction",
    { r = 255, g = 170, b = 75, a = 1 },
    getMinMax = getMinMax,
    name = "Unstable Affliction",
  },
}

DebuffData.warrior = {
  ["colossussmash"] = {
    "Colossus Smash",
    { r = 220, g = 150, b = 25, a = 1 },
    getMinMax = getMinMax,
    name = "Colossus Smash",
  },
  ["executionersprecision"] = {
    "Executioner's Precision",
    { r = 0.843, g = 0.196, b = 0.078, a = 1 },
    getMinMax = getStackingMinMax,
    name = "Executioner's Precision",
  },
  ["executionersprecision2"] = {
    "Executioner's Precision2",
    { r = 0.843, g = 0.196, b = 0.078, a = 1 },
    getMinMax = getStackingMinMax,
    name = "Executioner's Precision",
  },
}

DebuffData.deathknight = {
  ["virulentplague"] = {
    "Virulent Plague",
    { r = 185, g = 200, b = 150, a = 1 },
    getMinMax = getMinMax,
    name = "Virulent Plague",
  },
  ["festeringwound"] = {
    "Festering Wound",
    { r = 220, g = 44, b = 245, a = 1 },
    getMinMax = getStackingMinMax,
    name = "Festering Wound",
  },
  ["festeringwound2"] = {
    "Festering Wound2",
    { r = 220, g = 44, b = 245, a = 1 },
    getMinMax = getStackingMinMax,
    name = "Festering Wound",
  },
  ["festeringwound3"] = {
    "Festering Wound3",
    { r = 220, g = 44, b = 245, a = 1 },
    getMinMax = getStackingMinMax,
    name = "Festering Wound",
  },
  ["festeringwound4"] = {
    "Festering Wound4",
    { r = 220, g = 44, b = 245, a = 1 },
    getMinMax = getStackingMinMax,
    name = "Festering Wound",
  },
  ["festeringwound5"] = {
    "Festering Wound5",
    { r = 220, g = 44, b = 245, a = 1 },
    getMinMax = getStackingMinMax,
    name = "Festering Wound",
  },
  ["festeringwound6"] = {
    "Festering Wound6",
    { r = 220, g = 44, b = 245, a = 1 },
    getMinMax = getStackingMinMax,
    name = "Festering Wound",
  },
  ["festeringwound7"] = {
    "Festering Wound7",
    { r = 220, g = 44, b = 245, a = 1 },
    getMinMax = getStackingMinMax,
    name = "Festering Wound",
  },
  ["festeringwound8"] = {
    "Festering Wound8",
    { r = 220, g = 44, b = 245, a = 1 },
    getMinMax = getStackingMinMax,
    name = "Festering Wound",
  },
}

DebuffData.druid = {
  ["moonfire"] = {
    "Moonfire",
    { r = 195, g = 80, b = 220, a = 1 },
    getMinMax = getMinMax,
    name = "Moonfire",
  },
  ["sunfire"] = {
    "Sunfire",
    { r = 245, g = 165, b = 55, a = 1 },
    getMinMax = getMinMax,
    name = "Sunfire",
  },
  ["rip"] = {
    "Rip",
    { r = 170, g = 55, b = 25, a = 1 },
    getMinMax = getMinMax,
    name = "Rip",
  },
  ["rake"] = {
    "Rake",
    { r = 195, g = 65, b = 40, a = 1 },
    getMinMax = getMinMax,
    name = "Rake",
  },
  ["thrash"] = {
    "Thrash",
    { r = 200, g = 150, b = 115, a = 1 },
    getMinMax = getMinMax,
    name = "Thrash",
  },
}

DebuffData.mage = {}

DebuffData.monk = {}

DebuffData.shaman = {
  --  ["flameshock"]  = { "Flame Shock",  { r=225, g=175, b=15, a=1 }, getMinMax = getMinMax, name = "Flame Shock", },
}

DebuffData.hunter = {
  ["serpentsting"] = {
    "Serpent Sting",
    { r = 71, g = 172, b = 35, a = 1 },
    getMinMax = getMinMax,
    name = "Serpent Sting",
  },
}

DebuffData.paladin = {}

DebuffData.priest = {}

DebuffData.rogue = {}

--- Provides resource details.
--- @param class string The class identifier.
--- @param buff string The buff identifier.
--- @return table The resource data.
function DebuffData.get(class, buff)
  local res = DebuffData[strlower(class)][strlower(buff)]
  res.ssClass = "DebuffData"
  return res
end

--- Returns a reference to the target function.
--- @param name string The name of the function.
--- @return function The function reference.
function DebuffData.getFunction(name)
  if name == "getStackingMinMax" then
    return getStackingMinMax
  else
    return getMinMax
  end
end

--- Initializes a stored resource with actual values.
--- @param resource string The resource to initialize.
function DebuffData.init(resource)
  local index = strlower(string.gsub(resource[1], "[ :'%(%)]", ""))

  if DebuffData[ss.curClass][index] then
    -- update identifier, color and getMinMax functions.
    resource[1] = DebuffData[ss.curClass][index][1]
    resource[2] = DebuffData[ss.curClass][index][2]
    resource.getMinMax = DebuffData[ss.curClass][index].getMinMax
  else
    resource.getMinMax = function()
      return "", 0, 1, 1, 1
    end
  end
end

ss.Utils.addModule("DebuffData", DebuffData)
