local AddOnName, nsVars = ...
local ss = nsVars.SS

local IsShiftKeyDown = IsShiftKeyDown
local PlayerFrame, PlayerFrame_OnEvent = PlayerFrame, PlayerFrame_OnEvent
local GetShapeshiftFormID, PlaySoundFile = GetShapeshiftFormID, PlaySoundFile
local UnitClass, GetSpecialization, GetSpecializationInfo = UnitClass, GetSpecialization, GetSpecializationInfo
local select, pairs, math, strlower = select, pairs, math, strlower
local UnitAffectingCombat, GetTime, GetSpellCooldown = UnitAffectingCombat, GetTime, GetSpellCooldown
local floor, tostring = floor, tostring

ss.curClass = strlower(select(2, UnitClass("player")))

ss["gcdWatch"] = {
  max = 1,
  cur = 1,
};

function ss:round(num, idp)
  local mult = 10^(idp or 0)
  return math.floor(num * mult + 0.5) / mult
end

--function to make any frame object movable
function ss:MakeFrameMovable(frame,button,listener)
  local btnString = "LeftButton"
  if button then
    btnString = button
  end

  frame:SetClampedToScreen(true)
  frame:SetMovable(true)
  frame:EnableMouse(true)
  frame:RegisterForDrag(btnString)
  frame:SetScript("OnDragStart", function(self)
    if IsShiftKeyDown() then
      self:StartMoving()
    end
  end)
  frame:SetScript("OnDragStop", function(self)
    self:StopMovingOrSizing()
    if listener then
      listener(self)
    end
  end)
end

function ss:HandlePlayerFrame(show)
  if show then
    PlayerFrame:SetScript("OnEvent",PlayerFrame_OnEvent)
    PlayerFrame:Show()
  else
    PlayerFrame:SetScript("OnEvent",nil)
    PlayerFrame:Hide()
  end
end

function ss:valueFormat(val, formatting, petOverride)
  local newVal = val
  if petOverride == true then
    if val > 10000 then
      newVal = (floor((val/1000)*10)/10).."k"
    end
    return newVal;
  elseif formatting == "truncated" then
    if val > 1000000 then
      newVal = (floor((val/1000000)*10)/10) .."m"
    elseif val > 999 then
      newVal = (floor((val/1000)*10)/10) .."k"
    end
    return newVal;
  elseif formatting == "commaSeparated" then
    newVal = tostring(val):reverse():gsub("%d%d%d", "%1,"):reverse():gsub("^,", "");
    return newVal;
  else
    return newVal;
  end
end

function ss:GetRGBAValues(colorTable)
  if not colorTable then return 1,1,1,1; end
  return colorTable.r, colorTable.g, colorTable.b, colorTable.a
end

function ss:RegisterMode(sphere, specialization, label, fillColor, swirlColor, fontColor, fillInfo, fillTexture, monitorValue)
  if ss.db[sphere] and ss.db[sphere].modes then
    ss.db[sphere].modes[specialization] = ss.db[sphere].modes[specialization] or {};

    if ss.db[sphere].modes[specialization][label] then
      ss.db[sphere].modes[specialization][label]["fillColor"][2] = fillColor
      ss.db[sphere].modes[specialization][label]["fillInfo"] = fillInfo
      ss.db[sphere].modes[specialization][label]["fillTexture"] = fillTexture
    else
      ss.db[sphere].modes[specialization][label] = {
        ["fillColor"] = {
          fillColor,
        },
        ["swirlColor"] = {
          swirlColor,
        },
        ["fontColor"] = fontColor,
        ["fillInfo"] = fillInfo,
        ["fillTexture"] = {
          fillTexture,
        },
        ["monitorValue"] = monitorValue or 0,
      };
    end
  end
end

function ss:InitModes()
  ss.db.health.modes = {};
  ss.db.mainResource.modes = {};
  ss.db.additionalResource.modes = {};

  ss.profile.modeInfo.health.modeSpec = ss.curSpec
  ss.profile.modeInfo.mainResource.modeSpec = ss.curSpec
  ss.profile.modeInfo.additionalResource.modeSpec = ss.curSpec

  ss.profile.modeInfo.health.mode = "default"
  ss.profile.modeInfo.mainResource.mode = "default"
  ss.profile.modeInfo.additionalResource.mode = "default"

  local classModeData = ss.ClassResources.getModes(ss.ClassResources, strlower(ss.curClass))
  local i = 1

  for spec,modeList in pairs(classModeData) do
    for mode,resourceList in pairs(modeList) do
      for k,resourceData in pairs(resourceList) do
        if i < 4 then
          ss:RegisterMode(ss.private.layout.frameList[i], spec, mode, resourceData, resourceData[2], { {r=1,g=1,b=1,a=1}, {r=1,g=1,b=1,a=1}, }, {["fillGroup"] = "primary", ["fillId"] = "moon"}, ss.FillTextures.get("primary","moon"))
        elseif i == 4 then
          ss:RegisterMode(ss.private.layout.frameList[i], spec, mode, resourceData, resourceData[2], { {r=1,g=1,b=1,a=1}, {r=1,g=1,b=1,a=1}, }, {["fillGroup"] = "split", ["fillId"] = 1}, ss.FillTextures.get("split", 1))
        end
        i = i + 1
      end
      i = 1
    end
  end

  ss.db.Initialized = true
  ss.Layout:Refresh()
end

------------------------------
-- Liftcycle Event Handlers --
------------------------------

function ss:OnInitialized()
  self.MapMarker:Initialize()
  self.MenuButton:Initialize()
end

function ss:OnVariablesLoaded()
  ss.MapMarker.MapButton:Reposition(ss.global.general.MapMarker.locationAngle)
end

function ss:OnPlayerLoggedIn()
  self.curSpec = GetSpecialization()
  self.curSpecName = self.curSpec and select(2, GetSpecializationInfo(self.curSpec)) or "None"
  self.curSpec = strlower(self.curSpec)
  self.Layout:Initialize()

  if self.curClass == "druid" then
    self:AddEvent("UPDATE_SHAPESHIFT_FORM")
  end
end

function ss:OnPlayerSpecializationChanged()
  self.curSpec = GetSpecialization()
  self.curSpecName = self.curSpec and select(2, GetSpecializationInfo(self.curSpec)) or "None"
  self.curSpec = strlower(self.curSpec)

  self.Layout:OnSpecializationChanged()
end

function ss:OnUnitMaxPowerChanged()
  ss.Layout:OnUnitMaxPowerChanged()
end

function ss:OnPlayerShapeshift()
  if ss.curSpec and strlower(ss.curClass) == "druid" then
    self.Layout:Shapeshift(self.ShapeshiftToString.parse(GetShapeshiftFormID() or 0))
  end
end

function ss:OnRegenEnabled()
  if self.Layout and not UnitAffectingCombat("player") then
    self.Layout:EndCombat()
  end
end

function ss:OnRegenDisabled()
  if self.Layout and UnitAffectingCombat("player") then
    self.Layout:StartCombat()
  end
end

function ss:OnPetAvailable(name, hasPetSpells)
  self.Layout:TrackPet(self.db.track["pet"] and (hasPetSpells > 10) and name)
end

function ss:OnPlayerEnteredVehicle()
  ss.Layout:OnPlayerEnteredVehicle()
end

function ss:OnPlayerExitedVehicle()
  ss.Layout:OnPlayerExitedVehicle()
end

function ss:OnSpellCastSuccess(event, ...)
  self.updateGCD()
end

function ss.updateGCD()
  --  self.Debug.describe(self.dVars.spheres.health.general)
  --    local tempSpellList = ""
  --    wipe(gcdSpells)
  --    local _, _, offset, numSpells = GetSpellTabInfo(2)
  --    for i = 1, offset + numSpells do
  --      local slotType, slotID = GetSpellBookItemInfo(i, "spell")
  --      if slotType == "SPELL" then
  --        local slotName = GetSpellBookItemName(i, "spell")
  --        local spellName, _, _, _, _, _, spellID = GetSpellInfo(slotName)
  --        local spellCD = GetSpellBaseCooldown(spellID or 0) -- spellID can be nil during loading
  --        if spellCD == 0 then
  --          gcdSpells[spellID] = true
  --        end
  --      end
  --    end
  --    gcdMasterSpell = next(gcdSpells)
  --
  --    local start, duration = GetSpellCooldown(gcdMasterSpell)


  -- Get additiona args
  --    local eSpell, eRank, eLineID, eSpellID = ...
  --    --    local name, rank, icon, castingTime, minRange, maxRange, spellID = GetSpellInfo(eSpellID)
  --        local name, rank, icon, castingTime, minRange, maxRange, spellID = GetSpellInfo(61304)
  --local test = name .. rank .. icon .. castingTime .. minRange .. maxRange .. spellID

  --    realCastTime = castingTime / 1000


  --  local gcd = gcdVal - GCDReduc

  -- Get the GCD duration
  local tempStart, tempGCD = GetSpellCooldown(61304) -- get gcd, 61304 = gcd spell id
  --    DebugEventArgs = name .. " " .. tempGCD
  ss.gcdWatch.max = tempGCD


  -- TODO flag spells not in GCD
  if tempGCD > 0 then
    if not ss.gcdWatch.start then
      ss.gcdWatch.start = GetTime()
    end

    ss.gcdWatch.cur = 0
  end
end