--core/encounter.lua, tracks whether a boss encounter is in progress (backend).
--"during an encounter" is one of the context conditions that gate the FPS reductions
--(see core/context.lua). besides ENCOUNTER_START / ENCOUNTER_END, it also detects the player
--leaving an encounter when no ENCOUNTER_END fires -- e.g. hearthstoning out of the raid after
--dying. we deliberately do NOT use PLAYER_REGEN_ENABLED for this: dying mid-fight leaves combat
--while the encounter is still going, so it would end the encounter too early. instead we record
--the instance at ENCOUNTER_START and treat a zone change to a DIFFERENT instance while out of
--combat as the fight being over for this player (dying and running back keeps the same instance,
--so it is correctly ignored).

local _ = nil
local addonName, private = ...

private.Core = private.Core or {}

---@class FPSPP_Encounter
local Encounter = {}
private.Core.Encounter = Encounter

--true while a boss encounter is in progress.
Encounter.active = false
--the instance the active encounter began in (GetInstanceInfo's 8th return, the instance map id);
--used only to detect a later zone change out of the encounter. nil while no encounter is active.
Encounter.startInstanceID = nil

--frame used to receive the encounter and zone-change events.
local eventFrame = CreateFrame("Frame")

--returns true while a boss encounter is in progress.
---@return boolean
function Encounter:IsActive()
	return self.active
end

--updates the active flag for an ENCOUNTER_START / ENCOUNTER_END event and re-applies the
--profile (the context gate re-evaluates, applying or restoring the reductions if "during an
--encounter" is chosen). on start it records the current instance for the leave check below.
---@param event string
function Encounter:OnEncounterEvent(event)
	self.active = (event == "ENCOUNTER_START")
	if self.active then
		--8th return of GetInstanceInfo is the instance map id; remember it to spot a later leave.
		self.startInstanceID = select(8, GetInstanceInfo())
	end

	private.Core.Optimizer:ApplyProfile()
end

--handles a zone change. if an encounter is still marked active but the player is now out of
--combat AND in a different instance than where it started, they left the fight (hearthstone,
--teleport, released and left the instance) and no ENCOUNTER_END will arrive -- so end it here
--and re-apply, which restores the reductions. staying in combat, or dying and running back
--(same instance), leaves the encounter active as it should.
function Encounter:OnZoneChanged()
	if not self.active then
		return
	end

	if InCombatLockdown() then
		return
	end

	if select(8, GetInstanceInfo()) ~= self.startInstanceID then
		self.active = false
		private.Core.Optimizer:ApplyProfile()
	end
end

--registers the encounter and zone-change events; called once from OnInit.
function Encounter:Initialize()
	eventFrame:RegisterEvent("ENCOUNTER_START")
	eventFrame:RegisterEvent("ENCOUNTER_END")
	eventFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
	--keep the handler short: route zone changes to the leave check, encounter events to the flag.
	eventFrame:SetScript("OnEvent", function(_, event)
		if event == "PLAYER_ENTERING_WORLD" then
			Encounter:OnZoneChanged()
		else
			Encounter:OnEncounterEvent(event)
		end
	end)
end
