local mod	= DBM:NewMod(2656, "DBM-Party-Midnight", 1, 1299)
--local L		= mod:GetLocalizedStrings()--Nothing to localize for blank mods

mod:SetRevision("20260523021914")
mod:SetCreatureID(231626)--Kalis flagged as main boss, Latch (231629) is secondary
mod:SetEncounterID(3057)
--mod:SetHotfixNoticeRev(20250823000000)
--mod:SetMinSyncRevision(20250823000000)
mod:SetZone(2805)
mod.respawnTime = 29

mod:RegisterCombat("combat")

--NOTE: Heaving Yank happens at same time as Shriek and doesn't need it's own timer/warnings
local warnSplatteringSpew			= mod:NewCountAnnounce(472745, 2)

local specWarnHeavingYank			= mod:NewSpecialWarningBlizzYou(472793, nil, nil, nil, 3, 2, nil, nil, "behindboss")
local specWarnSplatteringSpew		= mod:NewSpecialWarningBlizzYou(472745, nil, nil, nil, 1, 2, nil, nil, "poolyou")
local specWarnBoneHack				= mod:NewSpecialWarningCount(472888, nil, nil, nil, 1, 2, nil, nil, "defensive")
local specWarnDebilitatingShriek	= mod:NewSpecialWarningCount(472736, nil, nil, nil, 2, 2, nil, nil, "aesoon")
local specWarnCurseofDarkness		= mod:NewSpecialWarningCount(474105, nil, nil, nil, 2, 2, nil, nil, "mobsoon")

local timerBoneHackCD				= mod:NewCDCountTimer(17.3, 472888, nil, "Tank", nil, 2, nil, DBM_COMMON_L.TANK_ICON)
local timerCurseofDarknessCD		= mod:NewCDCountTimer(22.7, 474105, nil, nil, 2, 3, nil, DBM_COMMON_L.CURSE_ICON)
local timerDebilitatingShriekCD		= mod:NewCDCountTimer(48, 472736, nil, nil, nil, 2, nil, DBM_COMMON_L.IMPORTANT_ICON)
local timerSplatteringSpewCD		= mod:NewCDCountTimer(27.3, 472777, nil, nil, nil, 3, nil, DBM_COMMON_L.HEALER_ICON)
--Midnight private aura replacements
--mod:AddPrivateAuraSoundOption({1253834,1215803}, true, 474105, 4, 1, "justrun", 2)--Curse of Darkness
--mod:AddPrivateAuraSoundOption(472793, true, 472795, 1, 1, "behindboss", 2)--Heaving Yank
--mod:AddPrivateAuraSoundOption(474129, true, 472745, 1, 1, "poolyou", 18)--Splattering Spew
--mod:AddPrivateAuraSoundOption(472777, true, 472777, 4, 2, "watchfeet", 8)--Gunk Splatter GTFO

mod.vb.boneHackCount = 0
mod.vb.curseofDarknessCount = 0
mod.vb.debilitatingShriekCount = 0
mod.vb.splatteringSpewCount = 0

local badStateDetected = false
local activeEventTypes = {}
local shriekTiming = {}

---@param self DBMMod
---@param dontSetAlerts boolean? Called on engage when we only want to set timeline parameters and not touch encounter alerts
local function setFallback(self, dontSetAlerts)
	if not dontSetAlerts then
		if self:IsTank() then
			specWarnBoneHack:SetAlert(25, "defensive", 2)
		end
		specWarnCurseofDarkness:SetAlert(26, "mobsoon", 2)
		specWarnDebilitatingShriek:SetAlert(27, "aesoon", 2)
		specWarnHeavingYank:SetAlert(29, "behindboss", 2, 4, 0)
		specWarnSplatteringSpew:SetAlert(28, "poolyou", 18, 2, 0)
	end
	local onlyColor = not DBM.Options.HideDBMBars
	timerBoneHackCD:SetTimeline(25, onlyColor)
	timerCurseofDarknessCD:SetTimeline(26, onlyColor)
	timerDebilitatingShriekCD:SetTimeline(27, onlyColor)
	timerSplatteringSpewCD:SetTimeline(28, onlyColor)
end

function mod:OnLimitedCombatStart()
	self:TLCountReset()
	self.vb.boneHackCount = 1
	self.vb.curseofDarknessCount = 1
	self.vb.debilitatingShriekCount = 1
	self.vb.splatteringSpewCount = 1
	badStateDetected = false
	activeEventTypes = {}
	shriekTiming = {}
	if DBM.Options.HardcodedTimer and not badStateDetected then
		self:IgnoreBlizzardAPI()
		self:RegisterShortTermEvents(
			"ENCOUNTER_TIMELINE_EVENT_ADDED",
			"ENCOUNTER_TIMELINE_EVENT_STATE_CHANGED"
		)
		setFallback(self, true)
	else
		setFallback(self)
	end
end

function mod:OnCombatEnd()
	self:TLCountReset()
	activeEventTypes = {}
	shriekTiming = {}
	self:UnregisterShortTermEvents()
end

do
	---@param self DBMMod
	---@param timer number
	---@param timerExact number
	---@param eventID number
	local function timersAll(self, timer, timerExact, eventID)
		--Logic confirmed against M+ pull logs only.
		if timer == 8 or timer == 27 then--Splattering Spew alternates 8.0 / 27.333
			activeEventTypes[eventID] = "splatteringSpew"
			timerSplatteringSpewCD:TLStart(timerExact, eventID, self:TLCountStart(eventID, "splatteringSpew", "splatteringSpewCount"))
		elseif timer == 17 then--Bone Hack at 17.333
			activeEventTypes[eventID] = "boneHack"
			timerBoneHackCD:TLStart(timerExact, eventID, self:TLCountStart(eventID, "boneHack", "boneHackCount"))
		elseif timer == 23 then--Curse of Darkness at 22.666
			activeEventTypes[eventID] = "curseofDarkness"
			timerCurseofDarknessCD:TLStart(timerExact, eventID, self:TLCountStart(eventID, "curseofDarkness", "curseofDarknessCount"))
		elseif timer == 48 then--Debilitating Shriek; successful cast resolves as state 3 when the cooldown expires
			activeEventTypes[eventID] = "debilitatingShriek"
			local shriekCount = self:TLCountStart(eventID, "debilitatingShriek", "debilitatingShriekCount")
			timerDebilitatingShriekCD:TLStart(timerExact, eventID, shriekCount)
			shriekTiming[eventID] = {
				startTime = GetTime(),
				duration = timerExact
			}
		else
			badStateDetected = true
			self:ResumeBlizzardAPI()
			self:UnregisterShortTermEvents()
			setFallback(self)
			DBM:Debug("|cffff0000Failed to match encounter timeline events to expected timers, falling back to Blizzard API|r", nil, nil, nil, true)
		end
	end

	function mod:ENCOUNTER_TIMELINE_EVENT_ADDED(eventInfo)
		if eventInfo.source ~= 0 then return end
		local eventID = eventInfo.id
		local timerExact = eventInfo.duration
		local timer = math.floor(timerExact + 0.5)
		if not badStateDetected then
			timersAll(self, timer, timerExact, eventID)
		end
	end

	function mod:ENCOUNTER_TIMELINE_EVENT_STATE_CHANGED(eventID)
		local eventState = C_EncounterTimeline.GetEventState(eventID)
		if not eventID or not eventState then return end
		local eventType = activeEventTypes[eventID]
		if eventState == 2 then
			activeEventTypes[eventID] = nil
			shriekTiming[eventID] = nil
			local finishedEventType, eventCount = self:TLCountFinish(eventID)
			if finishedEventType and eventCount then
				if finishedEventType == "splatteringSpew" then
					warnSplatteringSpew:Show(eventCount)
					specWarnSplatteringSpew:Show(eventCount, "poolyou")
				elseif finishedEventType == "boneHack" then
					if self:IsTank() then
						specWarnBoneHack:Show(eventCount)
						specWarnBoneHack:Play("defensive")
					end
				elseif finishedEventType == "curseofDarkness" then
					specWarnCurseofDarkness:Show(eventCount)
					specWarnCurseofDarkness:Play("mobsoon")
				end
			end
		elseif eventState == 3 then
			if eventType == "debilitatingShriek" then
				local timing = shriekTiming[eventID]
				local elapsed = timing and (GetTime() - timing.startTime) or 0
				local duration = timing and timing.duration or 0
				activeEventTypes[eventID] = nil
				shriekTiming[eventID] = nil
				if timing and math.abs(elapsed - duration) <= 1.0 then
					local finishedEventType, eventCount = self:TLCountFinish(eventID)
					if finishedEventType == "debilitatingShriek" and eventCount then
						specWarnDebilitatingShriek:Show(eventCount)
						specWarnDebilitatingShriek:Play("aesoon")
						specWarnHeavingYank:Show(eventCount, "behindboss")
					end
				else
					self:TLCountCancel(eventID)
				end
			else
				activeEventTypes[eventID] = nil
				shriekTiming[eventID] = nil
				self:TLCountCancel(eventID)
			end
		end
	end
end
