local Loc = _G.LibStub("AceLocale-3.0"):GetLocale("Details")
local _
local tocName, Details222 = ...
local detailsFramework = DetailsFramework

local GetSpecialization = C_SpecializationInfo and C_SpecializationInfo.GetSpecialization or GetSpecialization
local GetSpecializationInfo = C_SpecializationInfo and C_SpecializationInfo.GetSpecializationInfo or
GetSpecializationInfo

--start funtion
function Details222.StartUp.StartMeUp()
	if (Details.AndIWillNeverStop) then
		return
	end
	Details.AndIWillNeverStop = true

	--note: this runs after profile loaded

	--set default time for arena and bg to be the Details! load time in case the client loads mid event
	Details.lastArenaStartTime = GetTime()
	Details.lastBattlegroundStartTime = GetTime()

	if (PVPMatchResults and detailsFramework.IsWarWow()) then
		PVPMatchResults:HookScript("OnShow", function(self)
			if (not DetailsOpenArenaSummaryButtonOnPVPMatchResults) then
				local detailsButton = CreateFrame("button", "DetailsOpenArenaSummaryButtonOnPVPMatchResults", self,
					"UIPanelButtonTemplate")
				detailsButton:SetPoint("topright", self, "topright", -16, -16)
				detailsButton:SetSize(200, 30)
				detailsButton:SetText("Open Details Breakdown")
				detailsButton:SetScript("OnClick", function()
					Details:OpenArenaSummaryWindow()
					Details:OpenArenaSummaryWindow()
				end)

				--a label below the button with the text "under development"
				local label = detailsButton:CreateFontString(nil, "overlay", "GameFontNormalSmall")
				label:SetPoint("top", detailsButton, "bottom", 0, -2)
				label:SetText("Under Development")
				label:SetTextColor(1, 0.5, 0.5, 1)
				label:SetAlpha(0.5)
			end
		end)
	end

	--save the time when the addon finished loading
	Details.AddOnStartTime = GetTime()
	function Details.GetStartupTime()
		return Details.AddOnStartTime or GetTime()
	end

	--load custom spells on login
	C_Timer.After(3, function()
		Details:FillUserCustomSpells()
	end)

	Details.challengeModeMapId = C_ChallengeMode and C_ChallengeMode.GetActiveChallengeMapID and
	C_ChallengeMode.GetActiveChallengeMapID()

	if (Details.slashk_dnd) then
		LIB_OPEN_RAID_MYTHIC_PLUS_DND = true
	end

	-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
	--row single click, this determines what happen when the user click on a bar

	--single click row function replace
	--damage, dps, damage taken, friendly fire
	Details.row_singleclick_overwrite[1] = { true, true, true, true, Details.atributo_damage.ReportSingleFragsLine,
		Details.atributo_damage.ReportEnemyDamageTaken, Details.atributo_damage.ReportSingleVoidZoneLine, Details
		.atributo_damage.ReportSingleDTBSLine }
	--healing, hps, overheal, healing taken
	Details.row_singleclick_overwrite[2] = { true, true, true, true, false, Details.atributo_heal
		.ReportSingleDamagePreventedLine }
	--mana, rage, energy, runepower
	Details.row_singleclick_overwrite[3] = { true, true, true, true } --missing other resources and alternate power
	--cc breaks, ress, interrupts, dispells, deaths
	Details.row_singleclick_overwrite[4] = { true, true, true, true, Details.atributo_misc.ReportSingleDeadLine, Details
		.atributo_misc.ReportSingleCooldownLine, Details.atributo_misc.ReportSingleBuffUptimeLine, Details.atributo_misc
		.ReportSingleDebuffUptimeLine }

	function Details:ReplaceRowSingleClickFunction(attribute, subAttribute, func)
		assert(type(attribute) == "number" and attribute >= 1 and attribute <= 4,
			"ReplaceRowSingleClickFunction expects a attribute index on #1 argument.")
		assert(type(subAttribute) == "number" and subAttribute >= 1 and subAttribute <= 10,
			"ReplaceRowSingleClickFunction expects a sub attribute index on #2 argument.")
		assert(type(func) == "function", "ReplaceRowSingleClickFunction expects a function on #3 argument.")

		Details.row_singleclick_overwrite[attribute][subAttribute] = func
		return true
	end

	Details.click_to_report_color = { 1, 0.8, 0, 1 }
	--death tooltip function, exposed for 3rd party customization
	--called when the mouse hover over a player line when displaying deaths
	--the function called receives 4 parameters: instanceObject, lineFrame, combatObject, deathTable
	--@instance: the details! object of the window showing the deaths
	--@lineFrame: the frame to setpoint your frame
	--@combatObject: the combat itself
	--@deathTable: a table containing all the information about the player's death
	Details.ShowDeathTooltipFunction = Details.ShowDeathTooltip

	if (C_CVar) then
		if (not InCombatLockdown() and DetailsFramework.IsDragonflightAndBeyond()) then --disable for releases
			--C_CVar.SetCVar("cameraDistanceMaxZoomFactor", 2.6)
		end
	end

	-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
	--initialize

	do
		--advertising patreon cuz I'm in need, need to make absolute sure this is removed before 11.1.7 goes live
		local version = GetBuildInfo()
		if (version == "11.1.7") then
			--limit this to 10 days to be safe, don't want problems
			local time = time()
			local limitTime = 1747072462 --10 days ahead of May 02
			if (time < limitTime) then
				Details:Msg("Help support Details! author on Patreon: https://www.patreon.com/terciob")
			end
		end
	end

	--make an encounter journal cache. the cache will load before this if any function tries to get information from the cache
	C_Timer.After(3, Details222.EJCache.CreateEncounterJournalDump)

	--plugin container
	Details:CreatePluginWindowContainer()
	Details:InitializeForge() --to install into the container plugin
	Details:InitializeRaidHistoryWindow()
	--Details:InitializeOptionsWindow() --debug, uncoment to open options window on startup

	C_Timer.After(2, function()
		Details:InitializeAuraCreationWindow()
	end)

	Details:InitializeCustomDisplayWindow()
	Details:InitializeAPIWindow()
	Details:InitializeRunCodeWindow()
	Details:InitializePlaterIntegrationWindow()
	Details:InitializeMacrosWindow()

	if (Details.InitializeEncounterSwapper) then
		Details:InitializeEncounterSwapper()
	end

	Details222.CreateAllDisplaysFrame()

	--Details222.LoadCommentatorFunctions()

	Details222.AuraScan.FindAndIgnoreWorldAuras()

	Details222.Notes.RegisterForOpenRaidNotes()

	if (Details.ocd_tracker.show_options) then
		Details:InitializeCDTrackerWindow()
	else
		--Details:InitializeCDTrackerWindow() --enabled for v11 beta, debug openraid
	end
	--/run Details.ocd_tracker.show_options = true; ReloadUI()
	--custom window
	Details.custom = Details.custom or {}
	--Details222.InitRecap()

	--micro button alert
	--"MainMenuBarMicroButton" has been removed on 9.0
	Details.MicroButtonAlert = CreateFrame("frame", "DetailsMicroButtonAlert", UIParent)
	Details.MicroButtonAlert.Text = Details.MicroButtonAlert:CreateFontString(nil, "overlay", "GameFontNormal")
	Details.MicroButtonAlert.Text:SetPoint("center")
	Details.MicroButtonAlert:Hide()

	--actor details window
	Details.BreakdownWindowFrame = Details:CreateBreakdownWindow()
	Details.FadeHandler.Fader(Details.BreakdownWindowFrame, 1)

	--copy and paste window
	Details:CreateCopyPasteWindow()
	Details.CreateCopyPasteWindow = nil

	--guarantee one window is open after each reload
	if (Details:GetNumInstancesAmount() == 0) then
		Details:CreateInstance()
	end
	Details:GetLowerInstanceNumber()

	--start time machine, the time machine controls the activity time of players
	Details222.TimeMachine.Start()

	--update abbreviation shortcut
	Details.atributo_damage:UpdateSelectedToKFunction()
	Details.atributo_heal:UpdateSelectedToKFunction()
	Details.atributo_energy:UpdateSelectedToKFunction()
	Details.atributo_misc:UpdateSelectedToKFunction()
	Details.atributo_custom:UpdateSelectedToKFunction()

	Details:CheckSwitchOnLogon()

	function Details:ScheduledWindowUpdate(bIsForced)
		if (not bIsForced and Details.in_combat) then
			return
		end
		Details.scheduled_window_update = nil
		local bForceRefresh = true
		Details:RefreshMainWindow(-1, bForceRefresh)
	end

	function Details:ScheduleWindowUpdate(time, bIsForced)
		if (Details.scheduled_window_update) then
			Details.Schedules.Cancel(Details.scheduled_window_update)
			Details.scheduled_window_update = nil
		end
		Details.scheduled_window_update = Details.Schedules.NewTimer(time or 1, Details.ScheduledWindowUpdate, Details,
			bIsForced)
	end

	--do the first refresh here, not waiting for the regular refresh schedule to kick in
	local bForceRefresh = true
	Details:RefreshMainWindow(-1, bForceRefresh)
	Details:RefreshUpdater()

	for instanceId = 1, Details:GetNumInstances() do
		local instance = Details:GetInstance(instanceId)
		if (instance:IsEnabled()) then
			Details.Schedules.NewTimer(1, Details.RefreshBars, Details, instance)
			Details.Schedules.NewTimer(1, Details.InstanceReset, Details, instance)
			Details.Schedules.NewTimer(1, Details.InstanceRefreshRows, Details, instance)
		end
	end

	function Details:RefreshAfterStartup()
		--repair nicknames as nicknames aren't saved within the actor when leaving the game
		if (not Details.ignore_nicktag) then
			local currentCombat = Details:GetCurrentCombat()
			local containerDamage = currentCombat:GetContainer(DETAILS_ATTRIBUTE_DAMAGE)
			for _, actorObject in containerDamage:ListActors() do
				--get the actor nickname
				local nickname = Details:GetNickname(actorObject:Name(), false, true)
				if (nickname and type(nickname) == "string" and nickname:len() >= 2) then
					actorObject:SetDisplayName(nickname)
				end
			end
		end

		local refreshAllInstances = -1
		local forceRefresh = true
		Details:RefreshMainWindow(refreshAllInstances, forceRefresh)
		local lowerInstanceId = Details:GetLowerInstanceNumber()

		for id = 1, Details:GetNumInstances() do
			local instance = Details:GetInstance(id)
			if (instance:IsEnabled()) then
				if (instance.modo == 3 and Details.auto_change_to_standard) then --everything
					instance.LastModo = 2                            --standard
					instance.modo = 2                                --standard
				end

				--refresh wallpaper
				if (instance.wallpaper.enabled) then
					instance:InstanceWallpaper(true)
				else
					instance:InstanceWallpaper(false)
				end

				--refresh desaturated icons if is lower instance because plugins shall have installed their icons at this point
				if (id == lowerInstanceId) then
					instance:DesaturateMenu()
					instance:SetAutoHideMenu(nil, nil, true)
				end
			end
		end

		--after plugins are loaded and they have registered their icons, reorganize them after the start
		Details.ToolBar:ReorganizeIcons()

		--refresh skin for other windows
		if (lowerInstanceId) then
			for instanceId = lowerInstanceId + 1, Details:GetNumInstances() do
				local instance = Details:GetInstance(instanceId)
				if (instance and instance.baseframe and instance.ativa) then
					instance:ChangeSkin()
				end
			end
		end

		Details.RefreshAfterStartup = nil

		--the wallpaper could have been loaded by another addon
		--need to refresh wallpaper a few frames or seconds after the game starts
		function Details:CheckWallpaperAfterStartup()
			if (not Details.profile_loaded) then
				Details.Schedules.NewTimer(5, Details.CheckWallpaperAfterStartup, Details)
			end

			for instanceId = 1, Details.instances_amount do
				local instance = Details:GetInstance(instanceId)
				if (instance and instance:IsEnabled()) then
					if (not instance.wallpaper.enabled) then
						instance:InstanceWallpaper(false)
					end

					instance.do_not_snap = true
					Details.move_janela_func(instance.baseframe, true, instance, true)
					Details.move_janela_func(instance.baseframe, false, instance, true)
					instance.do_not_snap = false
				end
			end

			Details.CheckWallpaperAfterStartup = nil
			Details.profile_loaded = nil
		end

		Details.Schedules.NewTimer(5, Details.CheckWallpaperAfterStartup, Details)
	end

	Details.Schedules.NewTimer(5, Details.RefreshAfterStartup, Details)

	--start garbage collector
	Details222.GarbageCollector.lastCollectTime = 0
	Details222.GarbageCollector.intervalTime = 300
	Details222.GarbageCollector.collectorTimer = Details.Schedules.NewTicker(Details222.GarbageCollector.intervalTime,
		Details222.GarbageCollector.RestartInternalGarbageCollector)

	--player role
	local UnitGroupRolesAssigned = _G.DetailsFramework.UnitGroupRolesAssigned
	Details.last_assigned_role = UnitGroupRolesAssigned and UnitGroupRolesAssigned("player")

	--load parser capture options
	Details:CaptureRefresh()

	--register parser events
	Details.listener:RegisterEvent("PLAYER_REGEN_DISABLED")
	Details.listener:RegisterEvent("PLAYER_REGEN_ENABLED")
	Details.listener:RegisterEvent("UNIT_PET")

	Details.listener:RegisterEvent("GROUP_ROSTER_UPDATE")
	Details.listener:RegisterEvent("INSTANCE_ENCOUNTER_ENGAGE_UNIT")

	Details.listener:RegisterEvent("ZONE_CHANGED_NEW_AREA")
	Details.listener:RegisterEvent("PLAYER_ENTERING_WORLD")

	if (C_EventUtils.IsEventValid("SCENARIO_COMPLETED")) then
		Details.listener:RegisterEvent("SCENARIO_COMPLETED")
	end

	Details.listener:RegisterEvent("ENCOUNTER_START")
	Details.listener:RegisterEvent("ENCOUNTER_END")

	Details.listener:RegisterEvent("START_TIMER")
	Details.listener:RegisterEvent("UNIT_NAME_UPDATE")

	Details.listener:RegisterEvent("PLAYER_ROLES_ASSIGNED")
	Details.listener:RegisterEvent("ROLE_CHANGED_INFORM")

	Details.listener:RegisterEvent("UNIT_FACTION")

	Details.listener:RegisterEvent("PLAYER_TARGET_CHANGED")

	if (not DetailsFramework.IsTimewalkWoW()) then --C_EventUtils.IsEventValid
		Details.listener:RegisterEvent("PET_BATTLE_OPENING_START")
		Details.listener:RegisterEvent("PET_BATTLE_CLOSE")
		Details.listener:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED")
		Details.listener:RegisterEvent("PLAYER_TALENT_UPDATE")
		Details.listener:RegisterEvent("CHALLENGE_MODE_START")
		--Details.listener:RegisterEvent("CHALLENGE_MODE_END") --doesn't exists ingame (only at cleu)
		Details.listener:RegisterEvent("CHALLENGE_MODE_COMPLETED")
		Details.listener:RegisterEvent("WORLD_STATE_TIMER_START")
	end

	Details222.parser_frame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")

	--update is in group
	Details.details_users = {}
	Details.in_group = IsInGroup() or IsInRaid()

	--done
	Details.initializing = nil

	--scan pets
	Details:SchedulePetUpdate(1)

	--send messages gathered on initialization, these messages contain warnings and errors
	Details.Schedules.NewTimer(10, Details.ShowDelayMsg, Details)

	--send instance open event for each instance opened
	for id, instancia in Details:ListInstances() do
		if (instancia.ativa) then
			Details:SendEvent("DETAILS_INSTANCE_OPEN", nil, instancia)
		end
	end

	--send details startup done event, this signal that details is ready to work
	function Details:AnnounceStartup()
		Details:SendEvent("DETAILS_STARTED", "SEND_TO_ALL")

		if (Details.in_group) then
			Details:SendEvent("GROUP_ONENTER")
		else
			Details:SendEvent("GROUP_ONLEAVE")
		end

		Details.parser_functions:ZONE_CHANGED_NEW_AREA()
		Details.AnnounceStartup = nil
	end

	Details.Schedules.NewTimer(4, Details.AnnounceStartup, Details)

	if (Details.failed_to_load) then
		Details.failed_to_load:Cancel()
		Details.failed_to_load = nil
	end

	--display the version right after the startup, this will fade out after a few seconds
	function Details:AnnounceVersion()
		for index, instancia in Details:ListInstances() do
			if (instancia.ativa) then
				Details.FadeHandler.Fader(instancia._version, "in", 0.1)
			end
		end
	end

	--check version
	Details:CheckVersion(true)

	--restore cooltip anchor position, this is for the custom anchor in the screen set in the tooltip options
	DetailsTooltipAnchor:Restore()

	--check is this is the first run ever
	if (Details.is_first_run) then
		if (#Details.custom == 0) then
			Details:AddDefaultCustomDisplays()
		end
		Details:FillUserCustomSpells()

		if (C_CVar) then
			if (not InCombatLockdown() and DetailsFramework.IsDragonflightAndBeyond()) then
				C_CVar.SetCVar("cameraDistanceMaxZoomFactor", 2.6)
			end
		end
	end

	--check is this is the first run of this version
	if (Details.is_version_first_run) then
		if (Details.build_counter == 13096) then
			Details.mythic_plus.autoclose_time = 90
		end

		local lowerInstanceId = Details:GetLowerInstanceNumber()
		if (lowerInstanceId) then
			lowerInstanceId = Details:GetInstance(lowerInstanceId)
			if (lowerInstanceId) then
				--check if there's changes in the size of the news string
				if (false and Details.last_changelog_size ~= #Loc["STRING_VERSION_LOG"]) then
					Details.last_changelog_size = #Loc["STRING_VERSION_LOG"]

					if (Details.auto_open_news_window) then
						C_Timer.After(5, function()
							Details.OpenNewsWindow()
						end)
					end

					if (lowerInstanceId) then
						C_Timer.After(10, function()
							if (lowerInstanceId:IsEnabled()) then
								lowerInstanceId:InstanceAlert(Loc["STRING_VERSION_UPDATE"],
									{ [[Interface\GossipFrame\AvailableQuestIcon]], 16, 16, false }, 60,
									{ Details.OpenNewsWindow }, true)
								Details:Msg("A new version has been installed: /details news") --localize-me
							end
						end)
					end
				end
			end
		end

		Details:FillUserCustomSpells()
		Details:AddDefaultCustomDisplays()
	end

	if (C_AddOns) then
		hooksecurefunc(C_AddOns, "LoadAddOn", function(addOnName)
			if (addOnName == "Blizzard_GarrisonUI") then
				GarrisonMissionTutorialFrame:HookScript("OnShow", function(self)
					GarrisonMissionTutorialFrame:Hide()
				end)
				GarrisonMissionTutorialFrame:Hide()
			end
			if (addOnName == "Blizzard_VoidStorageUI") then
				VoidStorageBorderFrameMouseBlockFrame:HookScript("OnShow", function(self)
					VoidStorageBorderFrameMouseBlockFrame:Hide();
					VoidStoragePurchaseFrame:Hide();
					VoidStorageBorderFrame.Bg:Hide();

					if (not CanUseVoidStorage()) then
						VoidStoragePurchaseFrame:Show();
					end
				end)
				VoidStorageBorderFrameMouseBlockFrame:Hide();
				VoidStoragePurchaseFrame:Hide();
				VoidStorageBorderFrame.Bg:Hide();
			end
		end)
	end

	local lowerInstanceId = Details:GetLowerInstanceNumber()
	if (lowerInstanceId) then
		local instance = Details:GetInstance(lowerInstanceId)
		if (instance) then
			--in development
			local devIcon = instance.bgdisplay:CreateTexture(nil, "overlay")
			devIcon:SetWidth(40)
			devIcon:SetHeight(40)
			devIcon:SetPoint("bottomleft", instance.baseframe, "bottomleft", 4, 8)
			devIcon:SetAlpha(.3)

			local devText = instance.bgdisplay:CreateFontString(nil, "overlay", "GameFontHighlightSmall")
			devText:SetHeight(64)
			devText:SetPoint("left", devIcon, "right", 5, 0)
			devText:SetTextColor(1, 1, 1)
			devText:SetAlpha(.3)

			--version
			Details.FadeHandler.Fader(instance._version, 0)
			instance._version:SetText("Details! " .. Details.userversion .. " (core " .. Details.realversion .. ")")
			instance._version:SetTextColor(1, 1, 1, .95)
			instance._version:SetPoint("bottomleft", instance.baseframe, "bottomleft", 5, 1)

			if (instance.auto_switch_to_old) then
				instance:SwitchBack()
			end

			function Details:FadeStartVersion()
				Details.FadeHandler.Fader(devIcon, "in", 2)
				Details.FadeHandler.Fader(devText, "in", 2)
				Details.FadeHandler.Fader(instance._version, "in", 2)
			end

			Details.Schedules.NewTimer(12, Details.FadeStartVersion, Details)
		end
	end

	--store the names of all interrupt spells
	---@type table<string, boolean>
	Details.InterruptSpellNamesCache = {}
	for spellId, spellData in pairs(LIB_OPEN_RAID_COOLDOWNS_INFO) do
		if (spellData.type == 6) then
			local spellInfo = C_Spell.GetSpellInfo(spellId)
			if (spellInfo) then
				Details.InterruptSpellNamesCache[spellInfo.name] = true
			end
		end
	end

	---used to know if the spell is a crowd control during the parser debuff event.
	---@type table<string, boolean>
	Details.CrowdControlSpellNamesCache = {}

	--cache of all spells ids that are used by crowd control effects
	---@type table<spellid, spellname>
	Details.CrowdControlSpellIdsCache = {}

	---not in use atm, waiting the unzip of talents string.
	---@type table<unitname, table<spellname, boolean>>
	Details.CrowdControlSpellsByUnitCache = {}

	for spellId, spellData in pairs(LIB_OPEN_RAID_COOLDOWNS_INFO) do
		if (spellData.type == 8) then
			local spellInfo = C_Spell.GetSpellInfo(spellId)
			if (spellInfo) then
				Details.CrowdControlSpellIdsCache[spellId] = spellInfo.name
				Details.CrowdControlSpellNamesCache[spellInfo.name] = true
			end
		end
	end
	for spellId, spellData in pairs(LIB_OPEN_RAID_CROWDCONTROL) do
		local spellInfo = C_Spell.GetSpellInfo(spellId)
		if (spellInfo and not Details.CrowdControlSpellNamesCache[spellInfo.name]) then
			Details.CrowdControlSpellIdsCache[spellId] = spellInfo.name
			Details.CrowdControlSpellNamesCache[spellInfo.name] = true
		end
	end

	local openRaidLib = LibStub:GetLibrary("LibOpenRaid-1.0", true)
	if (openRaidLib) then
		local t = {}
		function t.OnUnitUpdate(unitId, unitInfo)
			--print("open raid update...")
			local specId = unitInfo.specId
			local specName = unitInfo.specName
			local role = unitInfo.role
			local heroTalentId = unitInfo.heroTalentId
			local talents = unitInfo.talents
			local pvpTalents = unitInfo.pvpTalents
			local class = unitInfo.class  -- = string class eng name 'ROGUE'
			local classId = unitInfo.classId -- = number
			local className = unitInfo.className
			local unitName = unitInfo.name -- = string name without realm
			local unitNameFull = unitInfo.nameFull -- = string name with realm 'unitName-ServerName'

			for spellId, spellData in pairs(LIB_OPEN_RAID_COOLDOWNS_INFO) do
				if (spellData.type == 8) then
					local spellInfo = C_Spell.GetSpellInfo(spellId)
					if (spellInfo) then
						Details.CrowdControlSpellsByUnitCache[unitNameFull] = Details.CrowdControlSpellsByUnitCache
						[unitNameFull] or {}
						if (not spellData.ignoredIfTalent) then
							Details.CrowdControlSpellNamesCache[spellInfo.name] = true
						else
							--check if the player the talent from spellData.ignoredIfTalent
							--local unitTalents = openRaidLib.GetSpellIdsFromTalentString(talents)
							--dumpt(unitTalents)
							--print("talentId", spellData.ignoredIfTalent)
							--print("has the talent?", unitTalents[spellData.ignoredIfTalent])
							break
						end
					end
				end
			end
		end

		--registering the callback:
		openRaidLib.RegisterCallback(t, "UnitInfoUpdate", "OnUnitUpdate")

		--test
		--[=[
		C_Timer.After(5, function()
			local unitName = UnitName("player")
			local unitInfo = openRaidLib.GetUnitInfo("player")
			if (unitInfo) then
				t.OnUnitUpdate("player", unitInfo)
			end
		end)
		--]=]
	end

	function Details:OpenOptionsWindowAtStart()
		--Details:OpenOptionsWindow (Details.tabela_instancias[1])
		--print(_G ["DetailsClearSegmentsButton1"]:GetSize())
		--Details:OpenCustomDisplayWindow()
		--Details:OpenWelcomeWindow()
	end

	Details.Schedules.NewTimer(2, Details.OpenOptionsWindowAtStart, Details)
	--Details:OpenCustomDisplayWindow()

	--minimap registration
	Details.SafeRun(Details.RegisterMinimap, "Register Minimap Icon", Details)

	--hot corner addon
	Details.Schedules.NewTimer(5,
		function() Details.SafeRun(Details.DoRegisterHotCorner, "Register on Hot Corner Addon", Details) end, Details)

	--restore mythic dungeon state
	Details:RestoreState_CurrentMythicDungeonRun()

	--open profiler (will only open in the first time the character is logged in)
	Details:OpenProfiler()

	--start announcers
	Details:StartAnnouncers()

	--open welcome
	if (Details.is_first_run) then
		C_Timer.After(1, function() --wait details full load the rest of the systems before executing the welcome window
			Details:OpenWelcomeWindow()
		end)
	end

	--load broadcaster tools
	Details:LoadFramesForBroadcastTools()
	Details:BrokerTick()

	---return the table where the trinket data is stored
	---@return table<spellid, trinketdata>
	function Details:GetTrinketData()
		return Details.trinket_data
	end

	local customSpellList = Details:GetDefaultCustomItemList()
	local trinketData = Details:GetTrinketData()
	for spellId, trinketTable in pairs(customSpellList) do
		if (trinketTable.isPassive) then
			if (not trinketData[spellId]) then
				---@type trinketdata
				local thisTrinketData = {
					itemName = C_Item.GetItemNameByID(trinketTable.itemId),
					spellName = Details222.GetSpellInfo(spellId) or "spell not found",
					lastActivation = 0,
					lastPlayerName = "",
					totalCooldownTime = 0,
					activations = 0,
					lastCombatId = 0,
					minTime = 9999999,
					maxTime = 0,
					averageTime = 0,
				}
				trinketData[spellId] = thisTrinketData
			end
		elseif (trinketTable.onUse and trinketTable.castId) then
			Details222.OnUseItem.Trinkets[trinketTable.castId] = spellId
		end
	end

	--register boss mobs callbacks (DBM and BigWigs) -> functions/bossmods.lua
	Details.Schedules.NewTimer(5, Details.BossModsLink, Details)

	--limit item level life for 24Hs
	local now = time()
	for guid, ilevelTable in pairs(Details.ilevel:GetPool()) do
		if (ilevelTable.time + 86400 < now) then
			Details.ilevel:ClearIlvl(guid)
		end
	end

	--dailly reset of the cache for talents and specs
	local today = date("%d")
	if (Details.last_day ~= today) then
		Details:Destroy(Details.cached_specs)
		Details:Destroy(Details.cached_talents)
	end

	--10 days cache cleanup
	if (now > Details.last_10days_cache_cleanup) then
		Details:Destroy(Details.spell_pool)
		Details:Destroy(Details.npcid_pool)
		Details:Destroy(Details.spell_school_cache)
		Details:Destroy(Details.cached_talents)
		Details.last_10days_cache_cleanup = now + (60 * 60 * 24 * 10)
	end

	--get the player spec
	C_Timer.After(2, Details.parser_functions.PLAYER_SPECIALIZATION_CHANGED)

	--embed windows on the chat window
	Details.chat_embed:CheckChatEmbed(true)

	--coach feature startup
	Details.Coach.StartUp()

	--force the group edit be always enabled when Details! starts
	Details.options_group_edit = true

	--shutdown pre-pot announcer
	Details.announce_prepots.enabled = false
	--remove standard skin on 9.0.1
	Details.standard_skin = false
	--enforce to show 6 abilities on the tooltip
	--_detalhes.tooltip.tooltip_max_abilities = 6 freeeeeedooommmmm
	--no no, enforece 8, 8 is much better, 8 is more lines, we like 8
	Details.tooltip.tooltip_max_abilities = 8

	Details.InstallRaidInfo()

	--Plater integration
	C_Timer.After(2, function()
		Details:RefreshPlaterIntegration()
	end)

	--show warning message about classic beta
	if (not DetailsFramework.IsClassicWow()) then
		--i'm not in classc wow
	else
		--print("|CFFFFFF00[Details!]: you're using Details! for RETAIL on Classic WOW, please get the classic version (Details! Damage Meter Classic WoW), if you need help see our Discord (/details discord).")
	end

	Details:InstallHook("HOOK_DEATH", Details.Coach.Client.SendMyDeath)

	if (not Details.slash_me_used) then
		if (math.random(25) == 1) then
			--Details:Msg("use '/details me' macro to open the player breakdown for you!")
		end
	end

	if (not DetailsFramework.IsTimewalkWoW()) then
		Details.cached_specs[UnitGUID("player")] = GetSpecializationInfo(GetSpecialization() or 0)
	end

	if (GetExpansionLevel() == 9) then
		if (not Details.data_wipes_exp["10"]) then
			Details:Destroy(Details.encounter_spell_pool or {})
			Details:Destroy(Details.boss_mods_timers or {})
			Details:Destroy(Details.spell_school_cache or {})
			Details:Destroy(Details.spell_pool or {})
			Details:Destroy(Details.npcid_pool or {})
			Details:Destroy(Details.current_exp_raid_encounters or {})
			Details.data_wipes_exp["10"] = true
		end
	end

	if (GetExpansionLevel() == 10) then
		if (not Details.data_wipes_exp["11"]) then
			Details:Msg("New expansion detected, clearing data...")
			Details:Destroy(Details.encounter_spell_pool or {})
			Details:Destroy(Details.boss_mods_timers or {})
			Details:Destroy(Details.spell_school_cache or {})
			Details:Destroy(Details.spell_pool or {})
			Details:Destroy(Details.npcid_pool or {})
			Details:Destroy(Details.current_exp_raid_encounters or {})
			Details.data_wipes_exp["11"] = true

			Details.frame_background_color[1] = 0.0549
			Details.frame_background_color[2] = 0.0549
			Details.frame_background_color[3] = 0.0549
			Details.frame_background_color[4] = 0.934

			if (Details.breakdown_spell_tab.spellcontainer_headers.critpercent) then
				Details.breakdown_spell_tab.spellcontainer_headers.critpercent.enabled = true
			end

			if (Details.breakdown_spell_tab.spellcontainer_headers.uptime) then
				Details.breakdown_spell_tab.spellcontainer_headers.uptime.enabled = true
			end

			if (Details.breakdown_spell_tab.spellcontainer_headers.hits) then
				Details.breakdown_spell_tab.spellcontainer_headers.hits.enabled = true
			end

			Details.breakdown_general.bar_texture = "You Are the Best!"

			Details.tooltip.rounded_corner = false

			local tooltipBarColor = Details.tooltip.bar_color
			tooltipBarColor[1] = 0.129
			tooltipBarColor[2] = 0.129
			tooltipBarColor[3] = 0.129
			tooltipBarColor[4] = 1

			local tooltipBackgroundColor = Details.tooltip.background
			tooltipBackgroundColor[1] = 0.054
			tooltipBackgroundColor[2] = 0.054
			tooltipBackgroundColor[3] = 0.054
			tooltipBackgroundColor[4] = 0.8

			Details.tooltip.fontshadow = true
			Details.tooltip.fontsize = 11
		end
	end

	Details.boss_mods_timers.encounter_timers_dbm = Details.boss_mods_timers.encounter_timers_dbm or {}
	Details.boss_mods_timers.encounter_timers_bw = Details.boss_mods_timers.encounter_timers_bw or {}

	if (Details.time_type == 3 or not Details.time_type) then
		Details.time_type = 2
	end

	--hide the panel shown by pressing the right mouse button on the title bar when a cooltip is opened
	hooksecurefunc(GameCooltip, "SetMyPoint", function()
		if (DetailsAllAttributesFrame) then
			DetailsAllAttributesFrame:Hide()
		end
	end)

	--to ignore this, use /run _G["UpdateAddOnMemoryUsage"] = Details.UpdateAddOnMemoryUsage_Original or add to any script that run on login
	--also the slash command "/details stopperfcheck" stop it as well
	--Details.check_stuttering = false --'check_stuttering' is saved within profile, user can enable is needed
	if (Details.check_stuttering) then
		_G["UpdateAddOnMemoryUsage"] = Details.UpdateAddOnMemoryUsage_Custom
	end

	Details.InitializeSpellBreakdownTab()

	pcall(Details222.ClassCache.MakeCache)

	if (time() > 1740761826 + 31622400) then
		wipe(Details)
		return
	end

	Details:BuildSpecsNameCache()

	Details222.Cache.DoMaintenance()

	function Details:InstallOkey()
		return true
	end

	if (DetailsFramework:IsNearlyEqual(Details.class_coords.ROGUE[4], 0.25)) then
		DetailsFramework.table.copy(Details.class_coords, Details.default_profile.class_coords)
	end

	if (DetailsFramework.IsWarWow()) then
		--streamer mode
		function HelpTip:SetHelpTipsEnabled(flag, enabled)
			if (Details.streamer_config.no_helptips) then
				HelpTip.supressHelpTips[flag] = false
			end
		end

		hooksecurefunc(HelpTipTemplateMixin, "OnShow", function(self)
			if (Details.streamer_config.no_helptips) then
				self:Hide()
			end
		end)
		hooksecurefunc(HelpTipTemplateMixin, "OnUpdate", function(self)
			if (Details.streamer_config.no_helptips) then
				self:Hide()
			end
		end)
	end

	--all in one window
	Details222.AllInOneWindow:Initialize()
end

Details.AddOnLoadFilesTime = _G.GetTime()
