local _, ns = ...
local SlickUI = ns.SlickUI

local LustAnnounce = {
	LastSpellID = nil,
	LastAnnouncement = 0,
	LastDetected = 0,
	LastGroupLustMessage = 0,
	PendingSerial = 0,
}
SlickUI.LustAnnounce = LustAnnounce

-- True Bloodlust-equivalent class, pet, and drum casts. Legacy pet and drum
-- spell IDs remain here because timewalking and scaled content can still use
-- older versions of those effects.
local LUST_SPELLS = {
	[2825] = true, -- Bloodlust
	[32182] = true, -- Heroism
	[80353] = true, -- Time Warp
	[264667] = true, -- Primal Rage
	[390386] = true, -- Fury of the Aspects
	[466904] = true, -- Harrier's Cry
	[90355] = true, -- Ancient Hysteria (legacy hunter pet)
	[160452] = true, -- Netherwinds (legacy hunter pet)
	[35475] = true, -- Drums of Battle
	[35476] = true, -- Greater Drums of Battle
	[146555] = true, -- Drums of Rage
	[178207] = true, -- Drums of Fury
	[230935] = true, -- Drums of the Mountain
	[256740] = true, -- Drums of the Maelstrom
	[309658] = true, -- Drums of Deathly Ferocity
	[381301] = true, -- Feral Hide Drums
	[444257] = true, -- Timeless Drums
	[1237547] = true, -- Void-Touched Drums
}

local function IsObservedGroupUnit(unit)
	if unit == "player" or unit == "pet" then return true end
	if type(unit) ~= "string" then return false end
	return unit:match("^party%d+$") ~= nil
		or unit:match("^raid%d+$") ~= nil
		or unit:match("^partypet%d+$") ~= nil
		or unit:match("^raidpet%d+$") ~= nil
end

function LustAnnounce:GetChannel()
	if IsInGroup and LE_PARTY_CATEGORY_INSTANCE and IsInGroup(LE_PARTY_CATEGORY_INSTANCE) then
		return "INSTANCE_CHAT"
	end
	if IsInRaid and IsInRaid() then return "RAID" end
	if IsInGroup and IsInGroup() then return "PARTY" end
end

local function LooksLikeLustAnnouncement(message)
	if type(message) ~= "string" then return false end
	local text = message:lower()
	return text:find("lust", 1, true) ~= nil
		or text:find("heroism", 1, true) ~= nil
		or text:find("time warp", 1, true) ~= nil
		or text:find("primal rage", 1, true) ~= nil
		or text:find("fury of the aspects", 1, true) ~= nil
		or text:find("harrier's cry", 1, true) ~= nil
		or text:find("drums", 1, true) ~= nil
end

-- Give every character a stable, slightly different delay. The earliest
-- enabled SlickUI client announces; all later clients see that chat message
-- and cancel. This also yields to another addon that announces immediately.
local function AnnouncementDelay()
	local guid = UnitGUID and UnitGUID("player")
	if type(guid) ~= "string" then return 0.8 end
	local hash = 0
	for index = 1, #guid do hash = (hash * 33 + guid:byte(index)) % 20 end
	return 0.25 + hash * 0.05
end

function LustAnnounce:HandleCast(unit, spellID)
	local settings = SlickUI.DB and SlickUI.DB.groupControls
	if not settings or settings.lustAnnounce ~= true then return end
	if not IsObservedGroupUnit(unit) or not LUST_SPELLS[spellID] then return end

	local channel = self:GetChannel()
	if not channel then return end

	local now = GetTime()
	if self.LastSpellID == spellID and now - self.LastDetected < 3 then return end

	local info = C_Spell and C_Spell.GetSpellInfo and C_Spell.GetSpellInfo(spellID)
	local spellName = info and info.name
	if type(spellName) ~= "string" or spellName == "" then spellName = "Bloodlust" end

	self.LastSpellID = spellID
	self.LastDetected = now
	self.PendingSerial = self.PendingSerial + 1
	local serial = self.PendingSerial
	local detectedAt = now
	C_Timer.After(AnnouncementDelay(), function()
		if serial ~= LustAnnounce.PendingSerial then return end
		if LustAnnounce.LastGroupLustMessage >= detectedAt then return end
		local currentSettings = SlickUI.DB and SlickUI.DB.groupControls
		if not currentSettings or currentSettings.lustAnnounce ~= true then return end
		local currentChannel = LustAnnounce:GetChannel()
		if not currentChannel then return end
		LustAnnounce.LastAnnouncement = GetTime()
		SendChatMessage("[SlickUI] Lust used: " .. spellName .. ".", currentChannel)
	end)
end

function LustAnnounce:Initialize()
	local frame = CreateFrame("Frame")
	frame:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
	frame:RegisterEvent("CHAT_MSG_PARTY")
	frame:RegisterEvent("CHAT_MSG_PARTY_LEADER")
	frame:RegisterEvent("CHAT_MSG_RAID")
	frame:RegisterEvent("CHAT_MSG_RAID_LEADER")
	frame:RegisterEvent("CHAT_MSG_INSTANCE_CHAT")
	frame:RegisterEvent("CHAT_MSG_INSTANCE_CHAT_LEADER")
	frame:SetScript("OnEvent", function(_, event, arg1, _, spellID)
		if event == "UNIT_SPELLCAST_SUCCEEDED" then
			if type(spellID) == "number" then LustAnnounce:HandleCast(arg1, spellID) end
		elseif LooksLikeLustAnnouncement(arg1) then
			LustAnnounce.LastGroupLustMessage = GetTime()
		end
	end)
	self.EventFrame = frame
end

SlickUI:RegisterModule("LustAnnounce", LustAnnounce)
