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

local UnitDebuff, GetTime = ss.APIUtils.UnitDebuff, GetTime
local string, tonumber, strlower, select = string, tonumber, strlower, select

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

--- Provides corruption information.
-- @param buff The debuff identifier.
-- @return The debuff information.
-- @see UnitDebuff().
--
local function getCorruption(buff)
  local duration, expires = select(5, UnitDebuff("target", buff, "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 information for Unstable Affliction.
-- @param buff
-- @return The debuff information.
-- @see UnitDebuff().
--
local function getUnstableAffliction(buff)
  local index = strlower(string.gsub(buff, "[ :'%(%)%d]", ""))
  local buffStack = string.gsub(buff, "[^%d]", "")
  local stack = 0

  buffStack = (buffStack and buffStack ~= "") and tonumber(buffStack) or 1

  for i = 0, 20 do
    -- Possible memory leak?
    local buffDetails = { UnitDebuff("target", i, "PLAYER HARMFUL") }
    if buffDetails and buffDetails[1] == "Unstable Affliction" then
      stack = stack + 1
    
      if stack == buffStack then
        -- Return values for the correct debuff.
        return index, (buffDetails[5] and 1 or 0), 1, (buffDetails[5] or 1), (buffDetails[6] or 1)
      end
    end
  end
  
  return index, 0, 1, 1, 1
end

--- Provides stacking debuff information.
-- @param spell The debuff identifier.
-- @return The debuff information.
-- @see UnitDebuff().
--
local function getStackingMinMax(spell)
  local buffName = string.gsub(spell, "%d", "")
  local index = strlower(string.gsub(spell, "[ :'%(%)%d]", ""))
  
  local stacks, _, duration, expires = select(3, UnitDebuff("target", buffName, "PLAYER HARMFUL"))
  
  if stacks then
    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

-- TODO: Add vulnerable for marks hunter
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", },
--  ["unstableaffliction"]  = { "Unstable Affliction",  { r=187, g=69, b=32, a=1 }, getMinMax = getUnstableAffliction, name = "Unstable Affliction", },
--  ["unstableaffliction2"] = { "Unstable Affliction2", { r=187, g=69, b=32, a=1 }, getMinMax = getUnstableAffliction, name = "Unstable Affliction", },
--  ["unstableaffliction3"] = { "Unstable Affliction3", { r=187, g=69, b=32, a=1 }, getMinMax = getUnstableAffliction, name = "Unstable Affliction", },
--  ["unstableaffliction4"] = { "Unstable Affliction4", { r=187, g=69, b=32, a=1 }, getMinMax = getUnstableAffliction, name = "Unstable Affliction", },
--  ["unstableaffliction5"] = { "Unstable Affliction5", { r=187, g=69, b=32, a=1 }, getMinMax = getUnstableAffliction, name = "Unstable Affliction", },
  ["agony"]               = { "Agony",                { r=187, g=69, b=32, a=1 }, getMinMax = getMinMax,             name = "Agony", },
}

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 The class identifier.
-- @param buff The buff identifier.
-- @return 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 The name of the function.
-- @return 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 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,0,0,0 end
  end
end

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