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

local ClassProcAlerts = { Active = {} }
SlickUI.ClassProcAlerts = ClassProcAlerts

local PROC_DEFINITIONS = {
	DRUID = {
		{ auraID = 69369, passiveID = 16974, specID = 103, fallbackName = "Predatory Swiftness" },
	},
}

local function Readable(value)
	if canaccessvalue and not canaccessvalue(value) then return false end
	if issecretvalue and issecretvalue(value) then return false end
	return value ~= nil
end

local function SpellDisplay(spellID, fallbackName)
	local info = C_Spell and C_Spell.GetSpellInfo and C_Spell.GetSpellInfo(spellID)
	local name = info and Readable(info.name) and info.name or fallbackName
	local icon = info and Readable(info.iconID) and info.iconID
	if not icon and C_Spell and C_Spell.GetSpellTexture then icon = C_Spell.GetSpellTexture(spellID) end
	return name, icon
end

function ClassProcAlerts:GetAvailableProcs()
	local _, class = UnitClass("player")
	local definitions = PROC_DEFINITIONS[class] or {}
	local specID
	if GetSpecialization and GetSpecializationInfo then
		local index = GetSpecialization()
		if index then specID = GetSpecializationInfo(index) end
	end
	local results = {}
	for _, definition in ipairs(definitions) do
		if not definition.specID or definition.specID == specID then
			local name, icon = SpellDisplay(definition.auraID, definition.fallbackName)
			results[#results + 1] = { auraID = definition.auraID, passiveID = definition.passiveID, name = name or definition.fallbackName, icon = icon }
		end
	end
	return results
end

function ClassProcAlerts:GetSettings(auraID)
	local settings = SlickUI.DB.classProcs
	settings.procs = settings.procs or {}
	settings.procs[auraID] = settings.procs[auraID] or { enabled = true, icon = true, sound = true }
	return settings.procs[auraID]
end

function ClassProcAlerts:IsAuraActive(auraID)
	if not C_UnitAuras or not C_UnitAuras.GetPlayerAuraBySpellID then return false end
	local ok, data = pcall(C_UnitAuras.GetPlayerAuraBySpellID, auraID)
	return ok and type(data) == "table"
end

function ClassProcAlerts:CreateAlertFrame()
	if self.AlertFrame then return self.AlertFrame end
	local frame = CreateFrame("Frame", "SlickUIClassProcAlert", UIParent)
	frame:SetSize(220, 128); frame:SetPoint("CENTER", UIParent, "CENTER", 0, 130); frame:SetFrameStrata("HIGH"); frame:Hide()
	local label = SlickUI.Theme:CreateText(frame, 18)
	label:SetPoint("TOP", 0, -2); label:SetTextColor(unpack(SlickUI.Theme.Colors.goldText)); frame.Label = label
	local holder = CreateFrame("Frame", nil, frame, "BackdropTemplate")
	holder:SetSize(76, 76); holder:SetPoint("TOP", label, "BOTTOM", 0, -10)
	holder:SetBackdrop({ bgFile = "Interface\\Buttons\\WHITE8X8", edgeFile = "Interface\\Buttons\\WHITE8X8", edgeSize = 3 })
	holder:SetBackdropColor(0.015, 0.018, 0.025, 0.96); holder:SetBackdropBorderColor(unpack(SlickUI.Theme.Colors.border))
	local icon = holder:CreateTexture(nil, "ARTWORK")
	icon:SetPoint("TOPLEFT", 4, -4); icon:SetPoint("BOTTOMRIGHT", -4, 4); icon:SetTexCoord(0.08, 0.92, 0.08, 0.92); frame.Icon = icon
	frame:SetScript("OnUpdate", function(alert, elapsed)
		alert.Elapsed = (alert.Elapsed or 0) + elapsed
		local progress = math.min(1, alert.Elapsed / 3.5)
		alert:SetAlpha(progress > 0.85 and (1 - progress) / 0.15 or 1)
		if progress >= 1 then alert:Hide(); alert:SetAlpha(1) end
	end)
	self.AlertFrame = frame
	return frame
end

function ClassProcAlerts:ShowAlert(proc, preview)
	local settings = self:GetSettings(proc.auraID)
	if preview or settings.icon ~= false then
		local frame = self:CreateAlertFrame()
		frame.Label:SetText(proc.name); frame.Icon:SetTexture(proc.icon or "Interface\\Icons\\INV_Misc_QuestionMark")
		frame.Elapsed = 0; frame:SetAlpha(1); frame:Show()
	end
	if (preview or settings.sound ~= false) and SlickUI.Alerts then SlickUI.Alerts:PlayAbilityReadySound() end
end

function ClassProcAlerts:Evaluate()
	local seen = {}
	for _, proc in ipairs(self:GetAvailableProcs()) do
		seen[proc.auraID] = true
		local settings = self:GetSettings(proc.auraID)
		local active = self:IsAuraActive(proc.auraID)
		if SlickUI.DB.classProcs.enabled ~= false and settings.enabled ~= false and active and not self.Active[proc.auraID] then self:ShowAlert(proc) end
		self.Active[proc.auraID] = active
	end
	for auraID in pairs(self.Active) do if not seen[auraID] then self.Active[auraID] = nil end end
end

function ClassProcAlerts:Preview(auraID)
	for _, proc in ipairs(self:GetAvailableProcs()) do if proc.auraID == auraID then self:ShowAlert(proc, true); return true end end
	return false
end

function ClassProcAlerts:Refresh()
	wipe(self.Active); self:Evaluate()
end

function ClassProcAlerts:Initialize()
	local events = CreateFrame("Frame")
	for _, event in ipairs({ "PLAYER_ENTERING_WORLD", "UNIT_AURA", "PLAYER_SPECIALIZATION_CHANGED", "TRAIT_CONFIG_UPDATED" }) do events:RegisterEvent(event) end
	events:SetScript("OnEvent", function(_, event, unit)
		if event ~= "UNIT_AURA" or unit == "player" then ClassProcAlerts:Evaluate() end
		if (event == "PLAYER_SPECIALIZATION_CHANGED" or event == "TRAIT_CONFIG_UPDATED") and SlickUI.Options then SlickUI.Options:RefreshClassBuffControls() end
	end)
	self.EventFrame = events; self:Evaluate()
end

SlickUI:RegisterModule("ClassProcAlerts", ClassProcAlerts)
