local _, Ns = ...

local FADE_DURATION = 0.35
local fadeAnim

local function StopFade()
	if fadeAnim then
		fadeAnim:Stop()
	end
end

local function FadeHUD(targetAlpha, callback)
	local hud = SinStatsFrame.HUD
	StopFade()
	if not fadeAnim then
		local ag = hud:CreateAnimationGroup()
		local anim = ag:CreateAnimation("Alpha")
		anim:SetDuration(FADE_DURATION)
		anim:SetSmoothing("IN_OUT")
		ag:SetScript("OnFinished", function()
			hud:SetAlpha(ag.targetAlpha)
			local mouseOver = Ns.Profile.Stats and Ns.Profile.Stats.EventMouseOver
			if not Ns.Profile.LockHUD then
				SinStatsFrame:SetAlpha(ag.targetAlpha)
				if ag.targetAlpha <= 0 and not mouseOver then
					SinStatsFrame:Hide()
				end
			end
			if ag.targetAlpha <= 0 and not mouseOver then
				hud:Hide()
			end
			if ag.onFinished then ag.onFinished() end
		end)
		fadeAnim = ag
		fadeAnim.anim = anim
	end
	local current = hud:GetAlpha()
	if current == targetAlpha then
		if targetAlpha <= 0 then
			local mouseOver = Ns.Profile.Stats and Ns.Profile.Stats.EventMouseOver
			if not mouseOver then
				hud:Hide()
				if not Ns.Profile.LockHUD then
					SinStatsFrame:Hide()
				end
			end
		elseif not Ns.Profile.LockHUD then
			SinStatsFrame:SetAlpha(targetAlpha)
		end
		if callback then callback() end
		return
	end
	hud:Show()
	fadeAnim.targetAlpha = targetAlpha
	fadeAnim.onFinished = callback
	fadeAnim.anim:SetFromAlpha(current)
	fadeAnim.anim:SetToAlpha(targetAlpha)
	fadeAnim:Play()
end

local INSTANCE_EVENTS = {
	{ type = "party",    key = "EventDungeon" },
	{ type = "raid",     key = "EventRaid" },
	{ type = "pvp",      key = "EventPvP" },
	{ type = "arena",    key = "EventArena" },
	{ type = "scenario", key = "EventDelves" },
}

local hideTimer

local function CancelHideTimer()
	if hideTimer then
		hideTimer:Cancel()
		hideTimer = nil
	end
end

local function ShowHUD()
	CancelHideTimer()
	Ns.Profile.HideHUD = false
	if not Ns.Profile.LockHUD then
		SinStatsFrame:SetAlpha(1)
		SinStatsFrame:Show()
	end
	SinStatsFrame.HUD.Background:SetAlpha(Ns.Profile.HUDBgAlpha or 0)
	FadeHUD(1)

	if #SinStatsFrame.HUD.StatList == 0 then
		Ns:QueueProfileRefresh()
	end
end

local function HideHUD()
	local stats = Ns.Profile.Stats
	local useOpacity = stats and stats.EventOpacity
	local targetAlpha = useOpacity and (stats.EventOpacityValue or 0.3) or 0

	local function DoHide()
		if not useOpacity then
			Ns.Profile.HideHUD = true
		end
		FadeHUD(targetAlpha)
	end

	if stats and stats.EventTimer and stats.EventTime then
		CancelHideTimer()
		hideTimer = C_Timer.NewTimer(stats.EventTime, function()
			hideTimer = nil
			DoHide()
		end)
	else
		CancelHideTimer()
		DoHide()
	end
end

local f = CreateFrame("Frame")
f:SetScript("OnEvent", function(self, event)

	if event == "PET_BATTLE_OPENING_START" then
		Ns.Profile.HideHUD = true
		FadeHUD(0)
		return
	elseif event == "PET_BATTLE_OVER" then
		Ns.Profile.HideHUD = false
		FadeHUD(1)
		return
	end

	local stats = Ns.Profile.Stats
	if not stats.EventEnable then return end


	if event == "PLAYER_ENTERING_WORLD" then
		local inInstance, instanceType = IsInInstance()

		if not Ns.CharPanel and not stats.EventCombat then
			local shouldShow, shouldHide = false, false

			for _, entry in ipairs(INSTANCE_EVENTS) do
				local enabled = stats[entry.key]
				if instanceType == entry.type then
					-- Inside this instance type
					if enabled then
						shouldShow = true
					elseif Ns.eventChecked then
						shouldHide = true
					end
				elseif enabled and not inInstance then
					shouldHide = true
				end
			end

			if stats.EventWorld and instanceType == "none" then
				shouldShow = true
				shouldHide = false
			end

			if shouldShow then
				ShowHUD()
			elseif shouldHide then
				HideHUD()
			end
		end

		if stats.EventCombat
			and not stats.EventWorld
			and not stats.EventDungeon
			and not stats.EventRaid
			and not stats.EventPvP
			and not stats.EventArena
			and not stats.EventDelves
			and (not UnitAffectingCombat("player") or not InCombatLockdown())
		then
			HideHUD()
		end

		if stats.EventTarget
			and not stats.EventWorld
			and not stats.EventDungeon
			and not stats.EventRaid
			and not stats.EventPvP
			and not stats.EventArena
			and not stats.EventDelves
			and not stats.EventCombat
			and not UnitExists("target")
		then
			HideHUD()
		end

	elseif event == "PLAYER_REGEN_DISABLED" then
		if stats.EventCombat and not Ns.CharPanel
			and (UnitAffectingCombat("player") or InCombatLockdown())
		then
			ShowHUD()
		end

	elseif event == "PLAYER_REGEN_ENABLED" then
		if stats.EventCombat and not Ns.CharPanel
			and (not UnitAffectingCombat("player") or not InCombatLockdown())
		then
			HideHUD()
		end

	elseif event == "PLAYER_TARGET_CHANGED" then
		if stats.EventTarget and not Ns.CharPanel then
			if UnitExists("target") then
				if not stats.EventTargetHostile or UnitIsEnemy("player", "target") then
					ShowHUD()
					return
				end
			end
			HideHUD()
		end
	end

	if stats.EventEnable and not Ns.CharPanel then
		if stats.EventResting then
			if IsResting() then
				HideHUD()
				return
			elseif event == "PLAYER_UPDATE_RESTING" then
				ShowHUD()
				return
			end
		end

		if stats.EventMounted then
			if IsMounted() then
				HideHUD()
				return
			elseif event == "PLAYER_MOUNT_DISPLAY_CHANGED" then
				ShowHUD()
				return
			end
		end
	end
end)

f:RegisterEvent("PLAYER_ENTERING_WORLD")
f:RegisterEvent("PLAYER_REGEN_DISABLED")
f:RegisterEvent("PLAYER_REGEN_ENABLED")
f:RegisterEvent("PET_BATTLE_OPENING_START")
f:RegisterEvent("PET_BATTLE_OVER")
f:RegisterEvent("PLAYER_UPDATE_RESTING")
f:RegisterEvent("PLAYER_MOUNT_DISPLAY_CHANGED")
f:RegisterEvent("PLAYER_TARGET_CHANGED")

-- Mouse Over Smart HUD (deferred — only created when the option is enabled)
local mouseOverFrame

local function EnableMouseOver()
	if mouseOverFrame then
		mouseOverFrame:Show()
		return
	end
	mouseOverFrame = CreateFrame("Frame", nil, UIParent)
	mouseOverFrame:SetPoint("TOPLEFT", SinStatsFrame, "TOPLEFT")
	mouseOverFrame:SetPoint("TOPRIGHT", SinStatsFrame, "TOPRIGHT")
	mouseOverFrame:SetHeight(SinStatsFrame:GetHeight())
	mouseOverFrame:SetMouseMotionEnabled(true)
	mouseOverFrame:SetMouseClickEnabled(false)
	mouseOverFrame:SetFrameStrata("FULLSCREEN_DIALOG")

	mouseOverFrame:SetScript("OnEnter", function()
		local stats = Ns.Profile.Stats
		if stats and stats.EventEnable and stats.EventMouseOver and not Ns.CharPanel then
			ShowHUD()
		end
	end)
	mouseOverFrame:SetScript("OnLeave", function()
		local stats = Ns.Profile.Stats
		if stats and stats.EventEnable and stats.EventMouseOver and not Ns.CharPanel then
			HideHUD()
		end
	end)
end

local function DisableMouseOver()
	if mouseOverFrame then
		mouseOverFrame:Hide()
	end
end

function Ns.ToggleMouseOver()
	local stats = Ns.Profile.Stats
	if stats and stats.EventEnable and stats.EventMouseOver then
		EnableMouseOver()
	else
		DisableMouseOver()
	end
end

function Ns.UpdateMouseOverSize(w, h)
	if mouseOverFrame and mouseOverFrame:IsShown() then
		mouseOverFrame:SetHeight(SinStatsFrame:GetHeight() + h)
		mouseOverFrame:SetWidth(w)
	end
end

-- Initialise on login if the option is already enabled
local moInit = CreateFrame("Frame")
moInit:RegisterEvent("PLAYER_LOGIN")
moInit:SetScript("OnEvent", function(self)
	self:UnregisterAllEvents()
	C_Timer.After(0, function()
		if Ns.Profile and Ns.Profile.Stats and Ns.Profile.Stats.EventEnable and Ns.Profile.Stats.EventMouseOver then
			EnableMouseOver()
		end
	end)
end)