local mod	= DBM:NewMod(1762, "DBM-Nighthold", nil, 786)
local L		= mod:GetLocalizedStrings()

mod:SetRevision(("$Revision: 17112 $"):sub(12, -3))
mod:SetCreatureID(103685)
mod:SetEncounterID(1862)
mod:SetZone()
mod:SetUsedIcons(8, 7, 6, 5, 4, 3, 2, 1)--Unknown carrions
mod:SetHotfixNoticeRev(16059)
mod.respawnTime = 30

mod:RegisterCombat("combat")

mod:RegisterEventsInCombat(
	"SPELL_CAST_START 212997 213238 213531 206365 216034 216723 215988",
	"SPELL_CAST_SUCCESS 212997 212794 208230",
	"SPELL_AURA_APPLIED 206480 212794 208230 216040 206466",
	"SPELL_AURA_APPLIED_DOSE 216024",
	"SPELL_AURA_REMOVED 212794 216040 206480",
	"SPELL_PERIODIC_DAMAGE 216027",
	"SPELL_PERIODIC_MISSED 216027",
	"UNIT_DIED",
	"CHAT_MSG_MONSTER_YELL"
)

--TODO, more review on Feast of Blood
--TODO, redo/update LFR/Normal timers since they probably also have phase 2 and phase 3 variations
 --(ability.id = 212997 or ability.id = 213238 or ability.id = 208230 or ability.id = 213531 or ability.id = 206365) and type = "begincast"
local warnCarrionPlague				= mod:NewTargetAnnounce(206480, 3)
local warnBrandOfArgus				= mod:NewTargetAnnounce(212794, 4)
local warnBloodFang					= mod:NewCountAnnounce("ej13528", 1, 24733)
--Nightborne
local warnVolatileWound				= mod:NewStackAnnounce(216024, 3, nil, false, 2)
--The Legion
local warnBurningSoul				= mod:NewTargetAnnounce(216040, 4)
local warnRingOfShadow				= mod:NewSpellAnnounce(216723, 3)

local specWarnCarrionPlague			= mod:NewSpecialWarningMoveAway(206480, nil, nil, nil, 1, 2)
local specWarnSeekerSwarm			= mod:NewSpecialWarningDodge(213238, nil, nil, nil, 2, 6)
local yellSeekerSwarm				= mod:NewYell(213238)--Carrion plague targets yell when it's relevant. On seeker swarm cast
local yellBrandOfArgus				= mod:NewPosYell(212794, 156225)--"Branded" short text
local specWarnFeastOfBlood			= mod:NewSpecialWarningRun(208230, nil, nil, nil, 1, 2)--Move away, or run? neither one really says "get 30 yards from boss"
local specWarnFeastOfBloodOther		= mod:NewSpecialWarningTaunt(208230, nil, nil, nil, 1, 2)
local specWarnEchoesOfVoid			= mod:NewSpecialWarningDodge(213531, nil, nil, nil, 3, 2)
local specWarnCarrionNightmare 		= mod:NewSpecialWarningDodge(215988, nil, nil, nil, 1, 2)
local specWarnAdds					= mod:NewSpecialWarningAdds(216726, "-Healer", nil, nil, 1, 2)
--Nightborne
local specWarnBlastNova				= mod:NewSpecialWarningInterrupt(216034, "HasInterrupt", nil, nil, 2, 2)
local specWarnNetherZoneGTFO		= mod:NewSpecialWarningMove(216027, nil, nil, nil, 2, 2)
--The Legion
local specWarnBurningSoul			= mod:NewSpecialWarningMoveAway(216040, nil, nil, nil, 1, 2)
local yellBurningSoul				= mod:NewYell(216040)

local timerCarrionPlagueCD			= mod:NewNextCountTimer(25, 212997, nil, nil, nil, 3)
local timerSeekerSwarmCD			= mod:NewNextCountTimer(25, 213238, nil, nil, nil, 3)
local timerBrandOfArgusCD			= mod:NewNextCountTimer(25, 212794, nil, nil, nil, 3)--Concider short timer 156225
local timerFeastOfBloodCD			= mod:NewNextCountTimer(25, 208230, nil, nil, 2, 1)
local timerEchoesOfVoidCD			= mod:NewNextCountTimer(65, 213531, nil, nil, nil, 2)
local timerIllusionaryNightCD		= mod:NewNextCountTimer(125, 206365, nil, nil, nil, 6)
local timerIllusionaryNight			= mod:NewBuffActiveTimer(32, 206365, nil, nil, nil, 6)
local timerAddsCD					= mod:NewAddsTimer(25, 216726, nil, "-Healer")
local timerCarrionNightmare			= mod:NewNextCountTimer(4, 215988, nil, nil, nil, 2)

local berserkTimer					= mod:NewBerserkTimer(463)

local countdownSeekerSwarm			= mod:NewCountdown(25, 213238)
local countdownEchoesOfVoid			= mod:NewCountdown("Alt65", 213531)
local countdownFeastOfBlood			= mod:NewCountdown("AltTwo25", 208230, "Tank")
local countdownNightPhase			= mod:NewCountdown(32, 206365, nil, nil, 10)
local countdownCarrionNightmare 	= mod:NewCountdown("Alt4", 215988, false, 2, 3)

mod:AddRangeFrameOption(8, 216040)
mod:AddSetIconOption("SetIconOnBrandOfArgus", 212794, true)
mod:AddInfoFrameOption(212794)

--With more data, the pattern gets distrupted later, but it's ALWAYS disrupted so multiple sequences needed to do it by phase (or just hard code ENTIRE sequence and not do it by phase?
--Carrion Plague: pull:5.0, 25.0, 35.6, 24.4, 75.0, 25.5, 35.6, 26.9, 75.0, 25.6, 40.6, 20.5, 53.6, 25.6
--Seeker Swarm:	  pull:25.0, 25.0, 35.0, 25.0, 75.0, 25.5, 37.5, 25.0, 75.0, 25.6, 36.1, 22.5, 56.1
--Brand of Argus: pull:15.0, 25.0, 35.0, 25.0, 75.0, 25.5, 32.5, 30.0, 75.0, 25.6, 36.1, 22.5, 56.1, 25.6",
--Feast of Blood: pull:20.0, 25.0, 35.0, 25.0, 75.0, 25.5, 37.5, 25.0, 75.1, 25.6, 36.2, 22.5, 56.1, 25.6"
--Carrion Plague, feast of blood, Seeker Swarm, brand of argus All Same in Phase 1
local P1SharedCastTimers = {0, 25, 35, 24.5}
--Phase 2 they start to fragment
local P2CarrionTimers = {0, 25.5, 35.6, 26.9}
local P2SeekerBloodTimers = {0, 25.5, 37.5, 25.0}--Seeker and Feast of Blood
local P2BrandTimers = {0, 25.5, 32.5, 30.0}
--less fragmented in phase 3
local P3CarrionTimers = {0, 25.6, 40.6, 20.5}
local P3SharedCastTimers = {0, 25.6, 36.1, 22.5}--Seeker, Brand, Feast

--Normal/LFR HAD different timers. Normal now matches heroic so assume LFR also does for now
--local sharedCastTimersFaster = {0, 15, 25, 14.5}--Carrion Plague, feast of blood, Seeker Swarm (faster on normal/LFR since no brand of argus)
local argusTargets = {}
local carrionDebuff, argusDebuff, batsName, essenceOfNightDebuff = DBM:GetSpellInfo(206480), DBM:GetSpellInfo(212794), DBM:EJ_GetSectionInfo(13528), DBM:GetSpellInfo(206466)
mod.vb.phase = 1
mod.vb.darkPhase = false
mod.vb.carrionPlagueCast = 0
mod.vb.feastOfBloodCast = 0
mod.vb.seekerSwarmCast = 0
mod.vb.brandOfArgusCast = 0
mod.vb.echoesOfVoidCast = 0
mod.vb.addsCount = 0
mod.vb.carrionNightmare = 0
mod.vb.batsKilled = 0
mod.vb.essenceCount = 0
mod.vb.CarrionPlagueCount = 0

local updateInfoFrame, breakMarks
do
	local lines = {}
	local sortedLines = {}
	local function addLine(key, value)
		-- sort by insertion order
		lines[key] = value
		sortedLines[#sortedLines + 1] = key
	end
	updateInfoFrame = function()
		table.wipe(lines)
		table.wipe(sortedLines)
		--Counts first, depending on phase
		if mod.vb.darkPhase then
			addLine(batsName, mod.vb.batsKilled)
			addLine(essenceOfNightDebuff, mod.vb.essenceCount)
		else
			addLine(carrionDebuff, mod.vb.CarrionPlagueCount)
		end
		--Argust playername list last
		for i = 1, #argusTargets do
			local name = argusTargets[i]
			local uId = DBM:GetRaidUnitId(name)
			if uId and UnitDebuff(uId, argusDebuff) then
				addLine(name, i)
			end
		end
		return lines, sortedLines
	end
	local playerName = UnitName("player")
	breakMarks = function (self, spellName)
		table.sort(argusTargets)
		warnBrandOfArgus:Show(table.concat(argusTargets, "<, >"))
		for i = 1, #argusTargets do
			local name = argusTargets[i]
			if not name then break end
			if not DBM:GetRaidUnitId(name) then break end
			if name == playerName then
				yellBrandOfArgus:Yell(i, i, i)
			end
			if self.Options.SetIconOnBrandOfArgus then
				self:SetIcon(name, i)
			end
		end
	end
end

function mod:OnCombatStart(delay)
	carrionDebuff, argusDebuff, batsName, essenceOfNightDebuff = DBM:GetSpellInfo(206480), DBM:GetSpellInfo(212794), DBM:EJ_GetSectionInfo(13528), DBM:GetSpellInfo(206466)
	self.vb.phase = 1
	self.vb.darkPhase = false
	self.vb.carrionPlagueCast = 0
	self.vb.feastOfBloodCast = 0
	self.vb.seekerSwarmCast = 0
	self.vb.brandOfArgusCast = 0
	self.vb.echoesOfVoidCast = 0
	self.vb.addsCount = 0
	self.vb.carrionNightmare = 0
	self.vb.batsKilled = 0
	self.vb.essenceCount = 0
	self.vb.CarrionPlagueCount = 0
	table.wipe(argusTargets)
	timerCarrionPlagueCD:Start(7-delay, 1)--Cast end
	timerFeastOfBloodCD:Start(20-delay, 1)
	countdownFeastOfBlood:Start(20-delay)
	timerSeekerSwarmCD:Start(25-delay, 1)
	countdownSeekerSwarm:Start(25-delay)
	timerEchoesOfVoidCD:Start(55-delay, 1)
	countdownEchoesOfVoid:Start(55-delay)
	timerIllusionaryNightCD:Start(130-delay, 1)
	if not self:IsEasy() then
		timerBrandOfArgusCD:Start(15-delay, 1)
		berserkTimer:Start(-delay)
	else
		berserkTimer:Start(523-delay)
	end
	if self.Options.InfoFrame then
		DBM.InfoFrame:SetHeader(OVERVIEW)
		DBM.InfoFrame:Show(8, "function", updateInfoFrame, false, false, true)
	end
end

function mod:OnCombatEnd()
--	self:UnregisterShortTermEvents()
	if self.Options.RangeFrame then
		DBM.RangeCheck:Hide()
	end
	if self.Options.InfoFrame then
		DBM.InfoFrame:Hide()
	end
end

function mod:SPELL_CAST_START(args)
	local spellId = args.spellId
	if spellId == 215988 then
		self.vb.carrionNightmare = self.vb.carrionNightmare + 1
		specWarnCarrionNightmare:Show()
		specWarnCarrionNightmare:Play("watchstep")
		if self.vb.carrionNightmare < 6 then
			timerCarrionNightmare:Start(nil, self.vb.carrionNightmare+1)
			countdownCarrionNightmare:Start()
		end
	elseif spellId == 212997 then
		if self.vb.darkPhase then--He casts it immediately after a Night phase ends
			self.vb.darkPhase = false
			self.vb.phase = self.vb.phase + 1
			self.vb.carrionPlagueCast = 0
			self.vb.feastOfBloodCast = 0
			self.vb.seekerSwarmCast = 0
			self.vb.brandOfArgusCast = 0
			self.vb.echoesOfVoidCast = 0
			self.vb.addsCount = 0
			DBM:Debug("First carrion Swarm after dark phase, Tichondrius returning", 2)
			--Timers same as combat start - 5
			if not self:IsEasy() then
				timerBrandOfArgusCD:Start(10, 1)
			end
			timerFeastOfBloodCD:Start(14.5, 1)
			countdownFeastOfBlood:Start(14.5)
			timerSeekerSwarmCD:Start(20, 1)
			countdownSeekerSwarm:Start(20)
			timerAddsCD:Start(20)
			timerIllusionaryNightCD:Start(123, 1)
			if self.vb.phase == 2 then--The Nightborne
				timerEchoesOfVoidCD:Start(50, 1)
				countdownEchoesOfVoid:Start(50)
			else--The Legion
				timerEchoesOfVoidCD:Start(55, 1)
				countdownEchoesOfVoid:Start(55)
			end
		end
	elseif spellId == 213238 then
		self.vb.seekerSwarmCast = self.vb.seekerSwarmCast + 1
		specWarnSeekerSwarm:Show(self.vb.seekerSwarmCast)
		local timer
		if self.vb.phase == 1 then
			timer = P1SharedCastTimers[self.vb.seekerSwarmCast+1]
		elseif self.vb.phase == 2 then
			timer = P2SeekerBloodTimers[self.vb.seekerSwarmCast+1]
		else--Assume phase 3+ are same, for now since no further mechancis introduced
			timer = P3SharedCastTimers[self.vb.seekerSwarmCast+1]
		end
		if timer then
			timerSeekerSwarmCD:Start(timer, self.vb.seekerSwarmCast+1)
			countdownSeekerSwarm:Start(timer)
		end
		if UnitDebuff("player", carrionDebuff) then
			yellSeekerSwarm:Yell()
			specWarnSeekerSwarm:Play("targetyou")
		else
			specWarnSeekerSwarm:Play("farfromline")
		end
	elseif spellId == 213531 then
		self.vb.echoesOfVoidCast = self.vb.echoesOfVoidCast + 1
		specWarnEchoesOfVoid:Show(self.vb.echoesOfVoidCast)
		specWarnEchoesOfVoid:Play("findshelter")
		if self.vb.echoesOfVoidCast == 1 then
			--Only cast twice per cycle
			if self.vb.phase == 1 then
				timerEchoesOfVoidCD:Start(65, 2)
				countdownEchoesOfVoid:Start(65)
			elseif self.vb.phase == 2 then
				timerEchoesOfVoidCD:Start(67.5, 2)
				countdownEchoesOfVoid:Start(67.5)
			else
				timerEchoesOfVoidCD:Start(59.7, 2)
				countdownEchoesOfVoid:Start(59.7)
			end
		end
	elseif spellId == 206365 then--Phase Change
		--stops may not be needed if sharedTimer Table works
		timerCarrionPlagueCD:Stop()
		timerSeekerSwarmCD:Stop()
		countdownSeekerSwarm:Cancel()
		timerBrandOfArgusCD:Stop()
		timerFeastOfBloodCD:Stop()
		countdownFeastOfBlood:Cancel()
		timerEchoesOfVoidCD:Stop()
		countdownEchoesOfVoid:Cancel()
		self.vb.darkPhase = true
		self.vb.carrionNightmare = 0
		self.vb.batsKilled = 0
		self.vb.essenceCount = 0
		timerIllusionaryNight:Start()
		countdownNightPhase:Start()
		timerCarrionNightmare:Start(6, 1)
		countdownCarrionNightmare:Start(6)
	elseif spellId == 216034 and self:CheckInterruptFilter(args.sourceGUID) then
		specWarnBlastNova:Show(args.sourceName)
		specWarnBlastNova:Play("kickcast")
	elseif spellId == 216723 then
		warnRingOfShadow:Show()
	end
end

function mod:SPELL_CAST_SUCCESS(args)
	local spellId = args.spellId
	if spellId == 212997 then
		self.vb.carrionPlagueCast = self.vb.carrionPlagueCast + 1
		local timer
		if self.vb.phase == 1 then
			timer = P1SharedCastTimers[self.vb.carrionPlagueCast+1]
		elseif self.vb.phase == 2 then
			timer = P2CarrionTimers[self.vb.carrionPlagueCast+1]
		else
			timer = P3CarrionTimers[self.vb.carrionPlagueCast+1]
		end
		if timer then
			timerCarrionPlagueCD:Start(timer, self.vb.carrionPlagueCast+1)
		end
	elseif spellId == 212794 then
		self.vb.brandOfArgusCast = self.vb.brandOfArgusCast + 1
		local timer
		if self.vb.phase == 1 then
			timer = P1SharedCastTimers[self.vb.brandOfArgusCast+1]
		elseif self.vb.phase == 2 then
			timer = P2BrandTimers[self.vb.brandOfArgusCast+1]
		else
			timer = P3SharedCastTimers[self.vb.brandOfArgusCast+1]
		end
		if timer then 
			timerBrandOfArgusCD:Start(timer, self.vb.brandOfArgusCast+1)
		end
	elseif spellId == 208230 then
		self.vb.feastOfBloodCast = self.vb.feastOfBloodCast + 1
		local timer
		if self.vb.phase == 1 then
			timer = P1SharedCastTimers[self.vb.feastOfBloodCast+1]
		elseif self.vb.phase == 2 then
			timer = P2SeekerBloodTimers[self.vb.feastOfBloodCast+1]
		else
			timer = P3SharedCastTimers[self.vb.feastOfBloodCast+1]
		end
		if timer then
			timerFeastOfBloodCD:Start(timer, self.vb.feastOfBloodCast+1)
			countdownFeastOfBlood:Start(timer)
		end
	end
end

function mod:SPELL_AURA_APPLIED(args)
	local spellId = args.spellId
	if spellId == 206480 then
		self.vb.CarrionPlagueCount = self.vb.CarrionPlagueCount + 1
		warnCarrionPlague:CombinedShow(0.5, args.destName)
		if args:IsPlayer() then
			specWarnCarrionPlague:Show()
			specWarnCarrionPlague:Play("scatter")
		end
		if self.Options.InfoFrame then
			DBM.InfoFrame:Update()
		end
	elseif spellId == 212794 then
		argusTargets[#argusTargets+1] = args.destName
		self:Unschedule(breakMarks)
		self:Schedule(0.5, breakMarks, self, args.spellName)
		if self.Options.InfoFrame then
			DBM.InfoFrame:Update()
		end
	elseif spellId == 208230 then
		if args:IsPlayer() then
			specWarnFeastOfBlood:Show()
			specWarnFeastOfBlood:Play("runout")
		else
			specWarnFeastOfBloodOther:Show(args.destName)
			specWarnFeastOfBloodOther:Play("tauntboss")
		end
	elseif spellId == 216040 then
		if args:IsPlayer() then
			specWarnBurningSoul:Show()
			yellBurningSoul:Yell()
			specWarnBurningSoul:Play("runout")
			if self.Options.RangeFrame then
				DBM.RangeCheck:Show(8)
			end
		else
			warnBurningSoul:Show(args.destName)
		end
	elseif spellId == 206466 then
		self.vb.essenceCount = self.vb.essenceCount + 1
		if self.Options.InfoFrame then
			DBM.InfoFrame:Update()
		end
	end
end

function mod:SPELL_AURA_APPLIED_DOSE(args)
	local spellId = args.spellId
	if spellId == 216024 then
		local amount = args.amount or 1
		if amount % 3 == 0 or amount > 6 then
			warnVolatileWound:Show(args.destName, amount)
		end
	end
end

function mod:SPELL_AURA_REMOVED(args)
	local spellId = args.spellId
	if spellId == 212794 then
		tDeleteItem(argusTargets, args.destName)
		if self.Options.SetIconOnBrandOfArgus then
			self:SetIcon(args.destName, 0)
		end
		if self.Options.InfoFrame then
			DBM.InfoFrame:Update()
		end
	elseif spellId == 216040 and args:IsPlayer() and self.Options.RangeFrame then
		DBM.RangeCheck:Hide()
	elseif spellId == 206480 then
		self.vb.CarrionPlagueCount = self.vb.CarrionPlagueCount - 1
		if self.Options.InfoFrame then
			DBM.InfoFrame:Update()
		end
	end
end

function mod:SPELL_PERIODIC_DAMAGE(_, _, _, _, destGUID, _, _, _, spellId)
	if spellId == 216027 and destGUID == UnitGUID("player") and self:AntiSpam(2, 1) then
		specWarnNetherZoneGTFO:Show()
		specWarnNetherZoneGTFO:Play("runaway")
	end
end
mod.SPELL_PERIODIC_MISSED = mod.SPELL_PERIODIC_DAMAGE

function mod:UNIT_DIED(args)
	local cid = self:GetCIDFromGUID(args.destGUID)
	if cid == 104326 then--Dark Phase bats
		self.vb.batsKilled = self.vb.batsKilled + 1
		if self.vb.batsKilled % 4 == 0 then
			warnBloodFang:Show(self.vb.batsKilled)
		end
		if self.Options.InfoFrame then
			DBM.InfoFrame:Update()
		end
	end
end

function mod:CHAT_MSG_MONSTER_YELL(msg, npc, _, _, target)
	if msg == L.Adds1 or msg:find(L.Adds1) or msg == L.Adds2 or msg:find(L.Adds2) then
		self:SendSync("Adds")--Syncing to help unlocalized clients
	end
end

function mod:OnSync(msg, targetname)
	if not self:IsInCombat() then return end
	if msg == "Adds" then
		self.vb.addsCount = self.vb.addsCount + 1
		specWarnAdds:Show()
		specWarnAdds:Play("killmob")
		if self.vb.phase == 2 then
			if self.vb.addsCount == 1 then
				timerAddsCD:Start(47)
			end
		else
			if self.vb.addsCount == 1 then
				timerAddsCD:Start(35)--ish, need relogging to confirm
			elseif self.vb.addsCount == 2 then
				timerAddsCD:Start(47)
			end
		end
	end
end
