local addonName              = "FuocoNote"
local nome_pg
local mainFrame, text1, scrollFrame
local collapsedBar
local MINW, MINH             = 200, 100
local MAXW, MAXH             = 1200, 1200
local StartW                 = 800
local db
local titleText
local leaderName             = nil
local openedMyConfig         = false
local ExpansionCollapsed     = {} -- [expName] = true/false (true = chiusa)
local EJBossCache            = {} -- EJBossCache[ejID][bossPos] = { instance, boss }
local UpdateText_updating    = false
local lootSet                = {}
local missingDropCount       = 0
local content1   -- upvalue (rimosso local da Initialize)
local questFrame -- frame reale tabella quest
local textBottom -- SimpleHTML per SaveInfo
local questRowPool           = {}
local ROW_H_MIN              = 18
-- misurazione altezza celle SimpleHTML (vedi MostraBossDaFare / MostraQuestDaFare)
local MEASURE_TEXT_H         = 4000 -- altezza temporanea del SimpleHTML in alto prima di misurare
local MEASURE_ROW_H          = 500  -- altezza temporanea delle celle riga prima di misurare
local MEASURE_DELAY          = 0.05 -- ritardo per far renderizzare prima di GetContentHeight
local ROW_BG_ALPHA           = 0.05 -- zebra striping: alpha righe pari
-- cache anti-flicker: si salta la ricostruzione delle righe se il contenuto non è cambiato
local lastBossSig, lastBossH, lastBossCount
local lastQuestSig, lastQuestH
local bossFrame -- frame tabella boss
local bossHeaderFrame
local bossRowPool            = {}
local BOSS_MIN_W             = 500
local QuestMinW              = 500
local UpdateText
local ScheduleUpdate
local TuttiILinkSonoCaricati = false
local forzaUdate1            = false
local FuocoGetKillStat
local InitKilledTimes
local WowVersion
local FuocoAutoAddWaypointsForZone
local CollectibleTypeCache   = {} -- itemID (number) -> "mount"|"toy"|"pet"|"illusion"|"transmog"|false
local FuocoLinkPopup  -- frame popup per i link esterni
------------------------
------------------------
------------------------
local StatNameByID           = {}
local StatNameCacheBuilt     = true -- da disattivare per test mostra l'achi
local not_show_item_loading	 = true -- da disattivare per test nasconde loading item
------------------------
------------------------
------------------------

-- formato localizzazione delle lingue:
--  test1 = {
--    enEN = "",
--    itIT = "",
--    esES = "",
--    deDE = "",
--    ruRU = "",
--    frFR = "",
--  },

local function GetBossCols(totalW)
	totalW      = math.max(totalW or BOSS_MIN_W, BOSS_MIN_W)
	local wNum  = 26 -- colonna # fissa
	local wRest = totalW - wNum - 10
	local wBoss = math.floor(wRest * 0.30)
	local wZona = math.floor(wRest * 0.20)
	local wDiff = math.floor(wRest * 0.12)
	local wDrop = wRest - wBoss - wZona - wDiff -- drop = colonna principale, prende più spazio
	return {
		{ x = 0,                                            w = wNum },
		{ x = wNum + 2,                                     w = wBoss },
		{ x = wNum + 2 + wBoss + 2,                         w = wZona },
		{ x = wNum + 2 + wBoss + 2 + wZona + 2,             w = wDrop },
		{ x = wNum + 2 + wBoss + 2 + wZona + 2 + wDrop + 2, w = wDiff },
	}
end

local function GetQuestCols(totalW)
	totalW      = math.max(totalW or QuestMinW, QuestMinW)
	local wNum  = 26                 -- colonna # fissa
	local wRest = totalW - wNum - 10 -- spazio rimanente con padding
	local wZona = math.floor(wRest * 0.22)
	local wObi  = math.floor(wRest * 0.36)
	local wDrop = wRest - wZona - wObi -- drop prende il resto (più spazio)
	return {
		{ x = 0,                               w = wNum },
		{ x = wNum + 2,                        w = wZona },
		{ x = wNum + 2 + wZona + 2,            w = wObi },
		{ x = wNum + 2 + wZona + 2 + wObi + 2, w = wDrop },
	}
end


local L = Fuoco.Lib.GetL()
local COLceleste1 = "|cff00ffff"
local COLrosso1 = "|cffff0000"
local COLverde1 = "|cff00ff00"
local COLverde2 = "|cff00ff99"
local COLgrigio1 = "|cffaaaaaa"
local COLgiallo1 = "|cffffff00"
local id_chat = 4

local function FuocoGetActiveEvent(EventAttivoID)
-- https://www.wowhead.com/recurring-events
-- https://www.wowhead.com/holidays
--	[559-40732] = "Outland Timewalking Dungeon Event",
--	[562-40731] = "Northrend Timewalking Dungeon Event",
--	[587-40733] = "Cataclysm Timewalking Dungeon Event",
--	[40734] = "Mists of Pandaria Timewalking",
--	[40735] = "Warlords of Draenor Timewalking",
--	[591-45886] = "Legion Dungeon Event",
--	67483 = "Torcia degli Spiriti" / buff da bonfire
-- verificati:
--  [341]   = "Midsummer Fire Festival" https://www.wowhead.com/event=341/midsummer-fire-festival
--  [1458]	= "Flussi Temporali Turbolenti"
--  [1720]	= "Evento bonus: Viaggi nel Tempo" >> DF ???
--  [1667]  BFA ?
--  [1705]  SL ?
--  [1583]  classic ?
--  [622]   TBC
--  [1720]  DF

    local function CalTimeToEpoch(t)
        if not t then return nil end
        return time({ year = t.year, month = t.month, day = t.monthDay, hour = t.hour, min = t.minute, sec = 0 })
    end

    local today = C_DateAndTime.GetCurrentCalendarTime()
    local nowEpoch = CalTimeToEpoch(today)
    local numEvents = C_Calendar.GetNumDayEvents(0, today.monthDay)
    for i = 1, numEvents do
        local event = C_Calendar.GetDayEvent(0, today.monthDay, i)
        if event and event.eventID == EventAttivoID then
            local startEpoch = CalTimeToEpoch(event.startTime)
            local endEpoch = CalTimeToEpoch(event.endTime)
            if startEpoch and endEpoch then
                if nowEpoch >= startEpoch and nowEpoch <= endEpoch then
                    return true
                end
            else
                return true
            end
        end
    end

    return false
end

----------------------------------------------------
-- tabellaLoot tabella di appoggio per drop senza quest o ancora non identificata
----------------------------------------------------

local tabellaLoot = { --oggetti per GZ senza metterli nella lista!!
	--232569, -- Chiave Runica Ciclonica - Zek'ul
	--192610, -- [Occhio Penetrante della Foresta]  x test
	--DEBUG
	--201466, -- fuori amirdrasil
	--208396, -- scintilla stagione 2
	--260639 -- osso fratturato fuori lunargenta
}
--------------------------------
-- tabella manuale: itemID del tomo -> spellID (o enchantID) dell'illusione
local IllusionIDByItemID = {
	[138798] = 5865,
	[138808] = 5384,
	[138807] = 5331,
	[138806] = 5335,
	[138835] = 5874,
	[138809] = 5336,
	[138805] = 4442,
	[138804] = 4445,
	[138836] = 5875,
	[138802] = 4097,
	[138955] = 5869,
	[138801] = 5392,
	[138800] = 3869,
	[138838] = 3273,
}

local FuocoLinkURLs = {
    [1] = "https://www.wowhead.com/news/the-unfazed-diver-pet-discovered-by-wow-secret-finders-381925",
	[2] = "https://www.wowhead.com/news/how-to-obtain-the-ice-guardians-sleetblade-cosmetic-sword-on-val-382003",
}
----------------------------------------------------
-- lista quest da fare
----------------------------------------------------

local IDQuest = { -- quest ripetibili
	-- {id (quest_done), note, tipo , idzona, drops[], npc, OggettoDiScambio}
	-- tipo=1 quest >> drop sempre {}
	-- tipo=2 kill,
	-- tipo=3 oggetti che potra a un OggettoDiScambio >>> scheggia crepitante >> alunira
	-- tipo=4 rare con spawn anche multipli
	-- tipo=5 achievements
	-- tipo=6 valuta?
	-- tipo=7 quest (come 1) con note >> nome quest
	-- tipo=8 paragon con fazione
	-- tipo=9 Renown
	-- tipo=10 solo note / link esterno
	------------------------------
	-- EventAttivoID
	-- link FuocoWayGetTitle tipo=1 oggetto, tipo=2 npcname

	-- MIDNIGHT
	--2395 -- Eversong Forest
	--2437 -- Zul'Aman
	--2413 -- Harandar
	--2405 -- voidstorm

	--DA_VERIFICARE se rimosso

	---------------------------------
	------- Viaggi nel tempo --------
	---------------------------------
	{ VersioneGioco = "12.0.7", tipo = 5,        idzona = 2393,                    achiID = 61463,                      drop = { 258884 } }, --  Spawn of Vyranoth - maestria dei flussi temporali 06-2026 ? DA_VERIFICARE se rimosso

	--[[ ---------------------------- 	
	-------------- DF ---------------
	--------------------------------- ]]
	{ -- TW df
		EventAttivoID = 1720,
		VersioneGioco = "12.0.7",
		tipo = 6,
		valutaID = 1166,
		quantity = "5000 " .. L.ogniuno1,
		idzona = 2112,
		drop = { 192778, 210140,
			232624, 205208,  238739, 257211, 257511, 257514, 257516, 257513 },
		npc = { 255019 },
		note = L.viaggi_nel_tempo.." (DF)\n".."|cff00ffff|Hfuoconoteway:" .. "2112" .. ":81.3 47:2:255019|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, -- mount TW 2026

	{ -- TW df
		EventAttivoID = 1720,
		VersioneGioco = "12.0.7",
		tipo = 6,
		valutaID = 1166,
		quantity = "500",
		idzona = 2112,
		drop = { 260170 },
		npc = { 255019 }, -- toy TW 2026
		note = L.viaggi_nel_tempo.." (DF)\n".."|cff00ffff|Hfuoconoteway:" .. "2112" .. ":81.3 47:2:255019|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},
	{ -- TW df
		EventAttivoID = 1720,
		VersioneGioco = "12.0.7",
		tipo = 6,
		valutaID = 1166,
		quantity = "750",
		idzona = 2112,
		drop = { 259899 },
		npc = { 255019 }, -- toy TW 2026
		note = L.viaggi_nel_tempo.." (DF)\n".."|cff00ffff|Hfuoconoteway:" .. "2112" .. ":81.3 47:2:255019|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},
	{ -- TW df
		EventAttivoID = 1720,
		VersioneGioco = "12.0.7",
		tipo = 6,
		valutaID = 1166,
		quantity = "1000",
		idzona = 2112,
		drop = { 259335 },
		npc = { 255019 }, -- toy TW 2026
		note = L.viaggi_nel_tempo.." (DF)\n".."|cff00ffff|Hfuoconoteway:" .. "2112" .. ":81.3 47:2:255019|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},

	{ -- TW df
		EventAttivoID = 1720,
		VersioneGioco = "12.0.7",
		tipo = 6,
		valutaID = 1166,
		quantity = "2200",
		idzona = 2112,
		drop = { 260885 },
		npc = { 255019 }, -- pet TW 2026
		note = L.viaggi_nel_tempo.." (DF)\n".."|cff00ffff|Hfuoconoteway:" .. "2112" .. ":81.3 47:2:255019|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},

	--[[ ---------------------------- 	
	-------------- DF fine ----------
	--------------------------------- ]]

	--[[ ---------------------------- 	
	---------------- BFA ------------
	--------------------------------- ]]

	{ -- TW BFA
		EventAttivoID = 1667,
		tipo = 6,
		valutaID = 1166,
		quantity = "5000",
		idzona = {1161, 1165},
		drop = { 205208, 232624, 238739, 245694, 245695, 257511, 257513, 257514, 257516 }, --mount
		npc = { 239840 },
		note = L.viaggi_nel_tempo.." (BFA)\n"..
				"|cff00ffff|Hfuoconoteway:" .. "1165" .. ":46.0 94.9:2:239840|h[" .. L.navigaTOMTOM .. "]|h|r\n"..
				"|cff00ffff|Hfuoconoteway:" .. "1161" .. ":70.9 17.2:2:239840|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},

	{ -- TW BFA
		EventAttivoID = 1667,
		tipo = 6,
		valutaID = 1166,
		quantity = "2200",
		idzona = {1161, 1165},
		drop = { 245543, 245574 }, -- pet
		npc = { 239840 },
		note = L.viaggi_nel_tempo.." (BFA)\n"..
				"|cff00ffff|Hfuoconoteway:" .. "1165" .. ":46.0 94.9:2:239840|h[" .. L.navigaTOMTOM .. "]|h|r\n"..
			   "|cff00ffff|Hfuoconoteway:" .. "1161" .. ":70.9 17.2:2:239840|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},
	{ -- TW BFA
		EventAttivoID = 1667,
		tipo = 6,
		valutaID = 1166,
		quantity = "1000",
		idzona = {1161, 1165},
		drop = { 245942, 246227 }, -- toy
		npc = { 239840 },
		note = L.viaggi_nel_tempo.." (BFA)\n"..
				"|cff00ffff|Hfuoconoteway:" .. "1165" .. ":46.0 94.9:2:239840|h[" .. L.navigaTOMTOM .. "]|h|r\n"..
				"|cff00ffff|Hfuoconoteway:" .. "1161" .. ":70.9 17.2:2:239840|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},

	--[[ ---------------------------- 	
	------------- BFA fine ----------
	--------------------------------- ]]

	--[[

	--- legion TW vendor
	{
		EventAttivoID = 45886,
		tipo = 6,
		valutaID = 1166,
		quantity = "5000",
		idzona = 627,
		drop = { 234721 },
		npc = { 180899 },
		note = "|cff00ffff|Hfuoconoteway:" .. "627" .. ":68.8 49.6:2:180899|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},
	{
		EventAttivoID = 45886,
		tipo = 6,
		valutaID = 1166,
		quantity = "5000",
		idzona = 627,
		drop = { 187595 },
		npc = { 180899 },
		note = "|cff00ffff|Hfuoconoteway:" .. "627" .. ":68.8 49.6:2:180899|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},
	{
		EventAttivoID = 45886,
		tipo = 6,
		valutaID = 1166,
		quantity = "5000",
		idzona = 627,
		drop = { 238739 },
		npc = { 180899 },
		note = "|cff00ffff|Hfuoconoteway:" .. "627" .. ":68.8 49.6:2:180899|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, --comune a più vendor ?
	{
		EventAttivoID = 45886,
		tipo = 6,
		valutaID = 1166,
		quantity = "5000",
		idzona = 627,
		drop = { 205208 },
		npc = { 180899 },
		note = "|cff00ffff|Hfuoconoteway:" .. "627" .. ":68.8 49.6:2:180899|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, --comune a più vendor ?
	{
		EventAttivoID = 45886,
		tipo = 6,
		valutaID = 1166,
		quantity = "5000",
		idzona = 627,
		drop = { 232624 },
		npc = { 180899 },
		note = "|cff00ffff|Hfuoconoteway:" .. "627" .. ":68.8 49.6:2:180899|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, --comune a più vendor ?
]]
	---------------------------------
	------- Viaggi nel tempo -------- FINE
	---------------------------------
--DA_VERIFICARE
--DA_VERIFICARE
--DA_VERIFICARE
	{ VersioneGioco = "12.1.1", tipo = 5, idzona = 2600, achiID = { 63333 }, drop = { 275657 } }, --Apophic Soul Crusher - Let Me Solo Him: Azta'rec

	{ VersioneGioco = "12.1.1", tipo = 5, idzona = 2600, achiID = { 62447 }, drop = { 276881 } }, --M+ 2k
	{ VersioneGioco = "12.1.1", tipo = 5, idzona = 2600, achiID = { 62449 }, drop = { 276882 } }, --M+ 2k


	{ VersioneGioco = "12.0.7", tipo=10, idzona = {2599}, drop = { 276290 }, note = "Heroic World Tier\n|cff00ffff|Hfuoconoteway:" .. "2599" .. ":70.5 84.3|h[" .. L.navigaTOMTOM .. "]|h|r\n|cff00ffff|Hfuocolink:2|h[" .. L.apriLink .. "]|h|r\n" }, -- Enchanted Hilt

	{ VersioneGioco = "12.0.7", tipo=10, idzona = {2472, 2600}, drop = { 246723 }, note = "|cff00ffff|Hfuocolink:1|h[" .. L.apriLink .. "]|h|r\n" },

	{ VersioneGioco = "12.0.7", EventAttivoID = 341, id = 0, tipo = 2, idzona = 260, drop = { 275464, 138838 }, npc = 25740 }, --Ahune - Grifalco Dipinto del Festival del Sole DA_VERIFICARE -- illusione

	-- Naigtal e val
	{ VersioneGioco = "12.0.7", tipo = 5, idzona = {2599, 2600}, achiID = { 62873 }, drop = { 274649 }, valutaID = 3316, quantity = "\n15", npc = 265559, note = 
		"|cff00ffff|Hfuoconoteway:" .. "2599" .. ":59 19.4:2:265559|h[" .. L.navigaTOMTOM .. "]|h|r\n"..
		"|cff00ffff|Hfuoconoteway:" .. "2600" .. ":47.6 81.2:1:265559|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, --Scavastelle del Sacerdote del Vuoto  -  Un viaggio tra le stelle
	{ VersioneGioco = "12.0.7", tipo = 5, idzona = {2599, 2600}, achiID = { 62874 }, drop = { 274650 }, valutaID = 3316, quantity = "\n15", npc = 265559, note = 
		"|cff00ffff|Hfuoconoteway:" .. "2599" .. ":59 19.4:2:265559|h[" .. L.navigaTOMTOM .. "]|h|r\n"..
		"|cff00ffff|Hfuoconoteway:" .. "2600" .. ":47.6 81.2:1:265559|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, --Corazza Nulla Fatuoforgiata  -  Un viaggio attraverso le stelle
	{ VersioneGioco = "12.0.7", tipo = 5, idzona = {2599, 2600}, achiID = { 63264 }, drop = { 275664 }, valutaID = 3316, quantity = "\n15",  npc = 265559, note = 
		"|cff00ffff|Hfuoconoteway:" .. "2599" .. ":59 19.4:2:265559|h[" .. L.navigaTOMTOM .. "]|h|r\n"..
		"|cff00ffff|Hfuoconoteway:" .. "2600" .. ":47.6 81.1:2:265559|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, --Divoratore Torturato  -  Scontri eroici

	{ VersioneGioco = "12.0.7", tipo = 5, idzona = {2599, 2600}, achiID = { 63349 }, drop = { 275662 },  valutaID = 3316, quantity = "\n15", npc = 265559, note = 
		"|cff00ffff|Hfuoconoteway:" .. "2599" .. ":59 19.4:2:265559|h[" .. L.navigaTOMTOM .. "]|h|r\n"..
		"|cff00ffff|Hfuoconoteway:" .. "2600" .. ":47.6 81.1:2:265559|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, --Maximus Gelidus -massacrfo dell'ultradonte
	{ VersioneGioco = "12.0.7", tipo = 6, idzona = {2599, 2600}, drop = { 275663 },  valutaID = 3316, quantity = "\n15", npc = 265559, note = 
		"|cff00ffff|Hfuoconoteway:" .. "2599" .. ":59 19.4:2:265559|h[" .. L.navigaTOMTOM .. "]|h|r\n"..
		"|cff00ffff|Hfuoconoteway:" .. "2600" .. ":47.6 81.1:2:265559|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, --pet
	{ VersioneGioco = "12.0.7", tipo = 10, idzona = {2599, 2600}, drop = { 252195 },  npc = 265559, note = 
		"|cff00ffff|Hfuoconoteway:" .. "2599" .. ":59 19.4:2:265559|h[" .. L.navigaTOMTOM .. "]|h|r\n"..
		"|cff00ffff|Hfuoconoteway:" .. "2600" .. ":47.6 81.1:2:265559|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, --pet
	

	-- campagna
	{ id = 86902,               tipo = 1,        note = L.queldanas1,              idzona = 2424,                       drop = { 257240 } }, -- quest campagna  quel'danas
	{ id = 88769,               tipo = 1,        note = L.queldanas1,              idzona = 2393,                       drop = { 260233, 258122 } }, -- quest campagna --61367 impresa
	{ id = 90867,               tipo = 1,        note = L.queldanas1,              idzona = 2424,                       drop = { 257143 } }, -- quest campagna  quel'danas

	{ id = 92899,               tipo = 1,        note = L.campagna1,              idzona = 2413,                       drop = { 246731 } }, -- quest campagna  Harandar
	{ id = 93012,               tipo = 1,        note = L.campagna1,              idzona = 2437,                       drop = { 268557 } }, -- quest campagna  zul'aman

	-- tutte le zone
	{ tipo = 6,                 valutaID = 3377, quantity = "6400 " .. L.ogniuno1, idzona = { 2395, 2437, 2413, 2405 }, drop = { 250782, 257197, 251633 }, npc = { 241928 } },

	-- lunargenta
	{
		id = 0,
		tipo = 1,
		note = "|cff00ffff|Hfuoconoteway:" .. "2393" .. ":42.2 58.8|h[" .. L.navigaTOMTOM .. "]|h|r\n",
		idzona = 2393,
		drop = { 275440, 275442, 275444, 275445, 275446, 275447, 174836, 182717, 187525, 187682, 192557, 199412, 204798, 209060, 213438, 226357, 235549, 248248, 237141, 247822 },
		npc = 197711,
		OggettoDiScambio = 275436
	}, -- [Cucciolo di Alasole]


	{ id = 93967,               tipo = 1, note = "\n|cff00ffff|Hfuoconoteway:" .. "2393" .. ":24.3 69.4:2:267838|h[" .. L.navigaTOMTOM .. "]|h|r\n", idzona = 2393,             drop = { 267838 } }, -- [Cucciolo di Alasole]

	-- SOLO STAGIONE 1 ???? DA_VERIFICARE se rimosso
	-- SOLO STAGIONE 1 ???? DA_VERIFICARE se rimosso
	-- preda: stagione 1
	{
		tipo = 9,
		idzona = 2393,
		drop = { 264434 },
		factionID = 2764,
		renownNeeded = 1,
		valutaID = 3392,
		quantity = 800,
		npc = 252956
		,
		note = "|cff00ffff|Hfuoconoteway:" .. "2393" .. ":43.5 47.5:2:252956|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},
	{
		tipo = 9,
		idzona = 2393,
		drop = { 264666 },
		factionID = 2764,
		renownNeeded = 1,
		valutaID = 3392,
		quantity = 600,
		npc = 252956
		,
		note = "|cff00ffff|Hfuoconoteway:" .. "2393" .. ":43.5 47.5:2:252956|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},
	{
		tipo = 9,
		idzona = 2393,
		drop = { 257191 },
		factionID = 2764,
		renownNeeded = 5,
		valutaID = 3392,
		quantity = 2000,
		npc = 252956
		,
		note = "|cff00ffff|Hfuoconoteway:" .. "2393" .. ":43.5 47.5:2:252956|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},
	{
		tipo = 9,
		idzona = 2393,
		drop = { 263933 },
		factionID = 2764,
		renownNeeded = 6,
		valutaID = 3392,
		quantity = 800,
		npc = 252956
		,
		note = "|cff00ffff|Hfuoconoteway:" .. "2393" .. ":43.5 47.5:2:252956|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},
	{
		tipo = 9,
		idzona = 2393,
		drop = { 259991 },
		factionID = 2764,
		renownNeeded = 9,
		valutaID = 3392,
		quantity = 1200,
		npc = 252956
		,
		note = "|cff00ffff|Hfuoconoteway:" .. "2393" .. ":43.5 47.5:2:252956|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},
	{
		tipo = 9,
		idzona = 2393,
		drop = { 257192 },
		factionID = 2764,
		renownNeeded = 10,
		valutaID = 3392,
		quantity = 2550,
		npc = 252956
		,
		note = "|cff00ffff|Hfuoconoteway:" .. "2393" .. ":43.5 47.5:2:252956|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},

	{
		tipo = 6,
		valutaID = 3393,
		quantity = "500",
		idzona = 2393,
		drop = { 268481 },
		npc = { 256084 }, --magisters-spell-bee-comb
		note = "|cff00ffff|Hfuoconoteway:" .. "2393" .. ":31.5 76.5:2:256084|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},
	{
		tipo = 6,
		valutaID = 3393,
		quantity = "200",
		idzona = 2393,
		drop = { 268455, 268456 },
		npc = { 256084 }, --magisters-spell-bee-comb
		note = "|cff00ffff|Hfuoconoteway:" .. "2393" .. ":31.5 76.5:2:256084|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},


	{ VersioneGioco = "12.0.5", tipo = 5, idzona = 2393,                                                                                             achiID = { 62562, 62563 }, drop = { 264348 }, valutaID = 3316, quantity = "\n6000", npc = 255503 }, --Unbound Manawyrm  -  Void Assaults 12.0.5
	{
		VersioneGioco = "12.0.5",
		tipo = 9,
		idzona = 2393,
		drop = { 268578 },
		factionID = 2792,
		renownNeeded = 8,
		valutaID = 3316,
		quantity = 4500,
		npc = 255503
		,
		note = "|cff00ffff|Hfuoconoteway:" .. "2393" .. ":48.6 50.4:2:255503|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},
	{ VersioneGioco = "12.0.5", tipo = 5, idzona = 2393, achiID = 62518, drop = { 270989 },         valutaID = 3316,                                                                                                                                                                             quantity = 1800, npc = 255503 }, --Cappy  -  Void Assaults 12.0.5
	{
		VersioneGioco = "12.0.5",
		tipo = 9,
		idzona = 2393,
		drop = { 270331 },
		factionID = 2792,
		renownNeeded = 6,
		valutaID = 3316,
		quantity = 1800,
		npc = 255503
		,
		note = "|cff00ffff|Hfuoconoteway:" .. "2393" .. ":48.6 50.4:2:255503|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},
	{
		VersioneGioco = "12.0.5",
		tipo = 9,
		idzona = 2393,
		drop = { 270330 },
		factionID = 2792,
		renownNeeded = 6,
		valutaID = 3316,
		quantity = 1800,
		npc = 255503
		,
		note = "|cff00ffff|Hfuoconoteway:" .. "2393" .. ":48.6 50.4:2:255503|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},

	-- sottomonete
	{
		tipo = 6,
		valutaID = 2803,
		quantity = 250,
		idzona = 2393,
		drop = { 267291 },
		npc = { 242398 },
		note = "|cff00ffff|Hfuoconoteway:" .. "2393" .. ":52.75 78:2:242398|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},
	{
		tipo = 6,
		valutaID = 2803,
		quantity = 5000,
		idzona = 2393,
		drop = { 262431 },
		npc = { 242398 },
		note = "|cff00ffff|Hfuoconoteway:" .. "2393" .. ":52.75 78:2:242398|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},
	{
		tipo = 6,
		valutaID = 2803,
		quantity = 10000,
		idzona = 2393,
		drop = { 262393 },
		npc = { 242398 },
		note = "|cff00ffff|Hfuoconoteway:" .. "2393" .. ":52.75 78:2:242398|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},
	{
		tipo = 6,
		valutaID = 2803,
		quantity = 10000,
		idzona = 2393,
		drop = { 262502 },
		npc = { 242398 },
		note = "|cff00ffff|Hfuoconoteway:" .. "2393" .. ":52.75 78:2:242398|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},

	{
		id = 0,
		tipo = 1,
		note = "|cff00ffff|Hfuoconoteway:" .. "2393" .. ":52.5 78.7|h[" .. L.navigaTOMTOM .. "]|h|r\n",
		idzona = 2393,
		drop = { 262500, 264414, 265100 },
		npc = 242399
	}, -- [Cucciolo di Alasole]



	--Eversong ritual site
	{ id = 0,                   npc = 1,  tipo = 2,      idzona = 2594,  drop = { 270041, 270063, 269999 }, note = L.ritualsite2 .. L.ritualsite1 .. "\n|cff00ffff|Hfuoconoteway:" .. "2594" .. ":66 74;62 77;48 72;41 73;38 64;47 46;53.4 55.4;50 55;56 41:1:270041,270063|h[" .. L.navigaTOMTOM .. "]|h|r\n" }, -- https://www.wowhead.com/ptr/item=270041/void-touched-snapdragon	---- insieme -- https://www.wowhead.com/item=270063/void-touched-lynx-kitten			---- insieme
	{
		VersioneGioco = "12.0.5",
		id = 0,
		tipo = 3,
		idzona = 2594,
		quantity = "",
		OggettoDiScambio = 272128,
		drop = { 270061 },
		note = L.ritualsite2 ..
			"|cff00ffff|Hfuoconoteway:" .. "2594" .. ":29 62:1:270061|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},
	{ id = 0,   npc = 1,       tipo = 2,       idzona = 2594,             drop = { 270062 },                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             note = L.ritualsite2 .. L.ritualsite3 .. "\n|cff00ffff|Hfuoconoteway:" .. "2594" .. ":49.5 60:1:270062|h[" .. L.navigaTOMTOM .. "]|h|r\n" },

	--eversong
	{ id = 0,   tipo = 4,      idzona = 2395,  drop = { 257156, 257147 }, npc = { { idnpc = 246332, id2Quest = 91280 }, { idnpc = 246633, id2Quest = 91315 }, { idnpc = 240129, id2Quest = 92392 }, { idnpc = 250582, id2Quest = 92366 }, { idnpc = 250719, id2Quest = 92391 }, { idnpc = 250683, id2Quest = 92389 }, { idnpc = 250754, id2Quest = 92393 }, { idnpc = 250876, id2Quest = 92409 }, { idnpc = 250841, id2Quest = 92404 }, { idnpc = 250780, id2Quest = 92395 }, { idnpc = 250826, id2Quest = 92403 }, { idnpc = 250806, id2Quest = 92399 }, { idnpc = 255302, id2Quest = 93550 }, { idnpc = 255329, id2Quest = 93555 }, { idnpc = 255348, id2Quest = 93561 }, { idnpc = 252465, id2Quest = 95011 }, { idnpc = 239864, id2Quest = 95010 } } }, -- [Zampalesta Ceruleo] -- [Dragofalco di Cobalto] eversong
	{ tipo = 5, idzona = 2395, achiID = 62190, drop = { 257144 } },  --  anima della festa achievements
	{
		tipo = 9,
		idzona = 2395,
		drop = { 257142 },
		factionID = 2710,
		renownNeeded = 19,
		valutaID = 3316,
		quantity = 8000,
		npc = 240838
		,
		note = "|cff00ffff|Hfuoconoteway:" .. "2395" .. ":43.5 47.5|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, -- Fiery Dragonhawk
	{
		tipo = 9,
		idzona = 2395,
		drop = { 257154 },
		factionID = 2710,
		renownNeeded = 17,
		valutaID = 3316,
		quantity = 6000,
		npc = 240838
		,
		note = "|cff00ffff|Hfuoconoteway:" .. "2395" .. ":43.5 47.5|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, -- Crimson Silvermoon Hawkstrider
	{
		tipo = 9,
		idzona = 2395,
		drop = { 259240 },
		factionID = 2710,
		renownNeeded = 13,
		valutaID = 3316,
		quantity = 4000,
		npc = 240838
		,
		note = "|cff00ffff|Hfuoconoteway:" .. "2395" .. ":43.5 47.5|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, -- Vino dei Sin'dorei
	{
		tipo = 9,
		idzona = 2395,
		drop = { 259224 },
		factionID = 2710,
		renownNeeded = 12,
		valutaID = 3316,
		quantity = 2500,
		npc = 240838
		,
		note = "|cff00ffff|Hfuoconoteway:" .. "2395" .. ":43.5 47.5|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, -- pet dragofalco-piccino
	--https://www.wowhead.com/it/factions/midnight/silvermoon-court per verificare gli id
	{
		tipo = 9,
		idzona = 2395,
		drop = { 264909 },
		factionID = 2711,
		renownNeeded = 6,
		valutaID = 3379,
		quantity = 200,
		npc = 242723
		,
		note = "|cff00ffff|Hfuoconoteway:" .. "2395" .. ":43.6 47.6|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, -- pet guizzo

	--Zul'Aman Ritual Site
	{
		VersioneGioco = "12.0.5",
		id = 0,
		tipo = 2,
		idzona = 2585,
		drop = { 269836 },
		note = L.ritualsite2 .. ": Zul'Aman" ..
			"\n|cff00ffff|Hfuoconoteway:" .. "2585" .. ":55.8 49.8:1:269836|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, -- Chubs
	{
		VersioneGioco = "12.0.5",
		id = 0,
		tipo = 2,
		idzona = 2585,
		drop = { 257225 },
		note = L.ritualsite2 .. ": Zul'Aman" ..
			"\n|cff00ffff|Hfuoconoteway:" .. "2585" .. ":56 38.5:1:257225|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, -- Witherbark Warbear Harness
	{
		VersioneGioco = "12.0.5",
		id = 0,
		tipo = 2,
		idzona = 2585,
		drop = { 269828 },
		note = L.ritualsite2 .. ": Zul'Aman" ..
			"\n|cff00ffff|Hfuoconoteway:" .. "2585" .. ":50.6 47.3;51.5 47.8:1:269828|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, -- Artiglio d'Aquila Corrotto dal Vuoto
	{
		VersioneGioco = "12.0.5",
		id = 0,
		tipo = 2,
		idzona = 2585,
		drop = { 269829 },
		note = L.ritualsite2 .. ": Zul'Aman" ..
			"\n|cff00ffff|Hfuoconoteway:" .. "2585" .. ":49.4 78.4;45.9 64.9:1:269829|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, -- Aquilotto Sfregiato dal Vuoto - pet

	--zul'aman
	{
		tipo = 6,
		valutaID = 3373,
		quantity = "2500",
		idzona = 2437,
		drop = { 274266 },
		npc = { 260180 },
		note = "|cff00ffff|Hfuoconoteway:" .. "2437" .. ":68.2 20.2:2:260180|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},

	{ id = 0,     tipo = 4,      idzona = 2437,                                                                                drop = { 257152, 257200 }, npc = { { idnpc = 242024, id2Quest = 89570 }, { idnpc = 242025, id2Quest = 89571 }, { idnpc = 242028, id2Quest = 89575 }, { idnpc = 245975, id2Quest = 91174 }, { idnpc = 247976, id2Quest = 91634 }, { idnpc = 242031, id2Quest = 89578 }, { idnpc = 242032, id2Quest = 89579 }, { idnpc = 242033, id2Quest = 89580 }, { idnpc = 242034, id2Quest = 89581 }, { idnpc = 242035, id2Quest = 89583 }, { idnpc = 242026, id2Quest = 89572 }, { idnpc = 242027, id2Quest = 89573 }, { idnpc = 245691, id2Quest = 91072 }, { idnpc = 245692, id2Quest = 91073 }, { idnpc = 242023, id2Quest = 89569 }, } }, -- Amani Sharptalon -- Escaped Witherbark Pango - Zul'Aman Rare Mobs
	{
		id = 0,
		tipo = 1,
		note = "|cff00ffff|Hfuoconoteway:" .. "2437" .. ":46 81;32 83;34 33;54 22;51 84|h[" .. L.navigaTOMTOM .. "]|h|r"
		,
		idzona = 2437,
		drop = { 257223 }
	}, -- Ancestral War Bear - Honored Warrior's Cache (object 539046 613727)

	{
		id = 0,
		tipo = 3,
		idzona = 2437,
		quantity = "\n1000",
		OggettoDiScambio = 259361,
		drop = { 257444 },
		note =
			"|cff00ffff|Hfuoconoteway:" .. "2437" .. ":44.7 44|h[" .. L.navigaTOMTOM .. "]|h|r"
	}, -- Hexed Vilefeather Eagle - Abandoned Ritual Skull (object 539047)
	-- RENOWN MOUNTS - MIDNIGHT
	{
		tipo = 9,
		idzona = 2437,
		drop = { 250889 },
		factionID = 2696,
		renownNeeded = 19,
		valutaID = 3316,
		quantity = 8000,
		npc = 240279,
		note = "|cff00ffff|Hfuoconoteway:" .. "2437" .. ":45.8 65.8:2:240279|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, -- Amani Windcaller
	{
		tipo = 9,
		idzona = 2437,
		drop = { 257219 },
		factionID = 2696,
		renownNeeded = 17,
		valutaID = 3316,
		quantity = 6000,
		npc = 240279,
		note = "|cff00ffff|Hfuoconoteway:" .. "2437" .. ":45.8 65.8:2:240279|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, -- Amani Blessed Bear
	{
		tipo = 9,
		idzona = 2437,
		drop = { 250974 },
		factionID = 2696,
		renownNeeded = 12,
		valutaID = 3316,
		quantity = 4000,
		npc = 240279,
		note = "|cff00ffff|Hfuoconoteway:" .. "2437" .. ":45.8 65.8:2:240279|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, -- Spinta Aerea di Akil'zon
	{
		tipo = 9,
		idzona = 2437,
		drop = { 250863 },
		factionID = 2696,
		renownNeeded = 12,
		valutaID = 3316,
		quantity = 2500,
		npc = 240279,
		note = "|cff00ffff|Hfuoconoteway:" .. "2437" .. ":45.8 65.8:2:240279|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, -- Naloki

	--Harandar
	{ tipo = 5,   idzona = 2413, achiID = 61263,                                                                               drop = { 263579 } },
	{ id = 93508, tipo = 1,      note = "|cff00ffff|Hfuoconoteway:" .. "2413" .. ":26.7 67.6|h[" .. L.navigaTOMTOM .. "]|h|r", idzona = 2413,             drop = { 260730 } },
	{ id = 0,     tipo = 4,      idzona = 2413,                                                                                drop = { 246735, 252012 }, npc = { { idnpc = 248741, id2Quest = 91832 }, { idnpc = 249844, id2Quest = 92137 }, { idnpc = 249849, id2Quest = 92142 }, { idnpc = 249902, id2Quest = 92148 }, { idnpc = 249962, id2Quest = 92154 }, { idnpc = 249997, id2Quest = 92161 }, { idnpc = 250086, id2Quest = 92168 }, { idnpc = 250180, id2Quest = 92170 }, { idnpc = 250226, id2Quest = 92172 }, { idnpc = 250231, id2Quest = 92176 }, { idnpc = 250246, id2Quest = 92183 }, { idnpc = 250317, id2Quest = 92190 }, { idnpc = 250321, id2Quest = 92191 }, { idnpc = 250347, id2Quest = 92193 }, { idnpc = 250358, id2Quest = 92194 }, } }, -- Rootstalker Grimlynx -- Vibrant Petalwing - Harandar Rare Mobs

	{
		id = 92265,
		tipo = 1,
		note = "|cff00ffff|Hfuoconoteway:" .. "2413" .. ":41.3 67.9;46.6 67.8|h[" .. L.navigaTOMTOM .. "]|h|r"
		,
		idzona = 2413,
		drop = { 256423 }
	}, -- Untainted Grove Crawler - Sporespawned Cache		--92246 + 92265
	{
		tipo = 6,
		valutaID = 3385,
		quantity = "(120) 10 " .. L.ogniuno1,
		idzona = 2413,
		drop = { 222988, 263580 },
		npc = { 251259 },
		note = "|cff00ffff|Hfuoconoteway:" .. "2413" .. ":49.2 54.4|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},
	-- {222988} Elder Glowmite              - Vendor Mothkeeper Wew'tam (npc=251259) 10 Luminous Dust
	-- {263580} Vivid Chloroceros           - Vendor Mothkeeper Wew'tam (npc=251259) 10 Luminous Dust

	{
		id = 0,
		tipo = 3,
		idzona = 2413,
		drop = { 256424 },
		quantity = 500,
		OggettoDiScambio = 255826,
		questPreRequisito = { 90467, 90468, 90469, 90470, 90474 },
		note = "|cff00ffff|Hfuoconoteway:" .. "2413" .. ":67.8 27.5;66.1 25.5|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, -- Echo of Aln'sharan - Aln'sharan (rare mob) Harandar??
	-- quest prerequisito start: https://www.wowhead.com/it/quest=90467/storie-del-cielo
	-- end: https://www.wowhead.com/it/quest=90474/la-leggenda-di-alnsharan
	--
	{
		id = 0,
		tipo = 3,
		idzona = 2413,
		quantity = "\n150",
		OggettoDiScambio = 260531,
		drop = { 252017 },
		note =
			"|cff00ffff|Hfuoconoteway:" .. "2413" .. ":40.7 28.1|h[" .. L.navigaTOMTOM .. "]|h|r"
	}, -- Ruddy Sporeglider - Peculiar Cauldron (object 614483)

	{
		id = 92424,
		tipo = 1,
		note = "|cff00ffff|Hfuoconoteway:" .. "2413" .. ":71.6 31|h[" .. L.navigaTOMTOM .. "]|h|r"
		,
		idzona = 2413,
		drop = { 258963 }
	}, --toy  [Paracadute del Saltafunghi]

	{
		id = 92436,
		tipo = 1,
		note = "|cff00ffff|Hfuoconoteway:" .. "2413" .. ":55.6 39.4|h[" .. L.navigaTOMTOM .. "]|h|r"
		,
		idzona = 2413,
		drop = { 258903 }
	}, --toy  [percival]

	-- harandar Naynar 240407
	{
		tipo = 9,
		idzona = 2413,
		drop = { 252014 },
		factionID = 2704,
		renownNeeded = 19,
		valutaID = 3316,
		quantity = 8000,
		npc = 240407
		,
		note = "|cff00ffff|Hfuoconoteway:" .. "2413" .. ":51 50.8|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, -- Cerulean Sporeglider
	{
		tipo = 9,
		idzona = 2413,
		drop = { 246734 },
		factionID = 2704,
		renownNeeded = 16,
		valutaID = 3316,
		quantity = 6000,
		npc = 240407
		,
		note = "|cff00ffff|Hfuoconoteway:" .. "2413" .. ":51 50.8|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, -- Fierce Grimlynx
	{
		tipo = 9,
		idzona = 2413,
		drop = { 256552 },
		factionID = 2704,
		renownNeeded = 13,
		valutaID = 3316,
		quantity = 4000,
		npc = 240407
		,
		note = "|cff00ffff|Hfuoconoteway:" .. "2413" .. ":51 50.8|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, --Seme dei Radicei Verdeggiante
	{
		tipo = 9,
		idzona = 2413,
		drop = { 259337 },
		factionID = 2704,
		renownNeeded = 1,
		valutaID = 3316,
		quantity = 2500,
		npc = 240407,
		note = "|cff00ffff|Hfuoconoteway:" .. "2413" .. ":51, 50.8|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	},                                                                                                                                                             -- Croccantino

	{ id = 90745, tipo = 7,      note = "|cff00ffff|Hfuoconoteway:" .. "2413" .. ":53.3 49.5|h[" .. L.navigaTOMTOM .. "]|h|r\n", idzona = 2413,    drop = { 260306 } }, -- culla vuota - leggenda

	-- Reputation: Drop da item (Slayer's Duellum Trove)
	{ tipo = 8,   idzona = 2444, drop = { 257176, 264892 },                                                                              factionID = 2770, note = "|cff00ffff|Hfuoconoteway:" .. "2444" .. ":39.2 81:2:258328|h[" .. L.navigaTOMTOM .. "]|h|r" },
	{
		tipo = 6,
		valutaID = 3316,
		quantity = " 6000,6000,4000,2500 ",
		idzona = 2444,
		drop = { 257448, 257447, 264517, 265035 },
		npc = { 258328 },
		note = "|cff00ffff|Hfuoconoteway:" .. "2444" .. ":39.2 81:2:258328|h[" .. L.navigaTOMTOM .. "]|h|r"
	},

	-- voidstorm
	{ id = 0,     tipo = 4,      idzona = 2405,  drop = { 257085, 260635 }, npc = { { idnpc = 244272, id2Quest = 90805 }, { idnpc = 238498, id2Quest = 91050 }, { idnpc = 241443, id2Quest = 91048 }, { idnpc = 256922, id2Quest = 93966 }, { idnpc = 256923, id2Quest = 93946 }, { idnpc = 256924, id2Quest = 93944 }, { idnpc = 256925, id2Quest = 93947 }, { idnpc = 256926, id2Quest = 93934 }, { idnpc = 256808, id2Quest = 93895 }, { idnpc = 257027, id2Quest = 93953 }, { idnpc = 256770, id2Quest = 93884 }, { idnpc = 245182, id2Quest = 91047 }, { idnpc = 245044, id2Quest = 91051 }, { idnpc = 256821, id2Quest = 93896 }, } },
	{
		id = 93237,
		tipo = 1,
		note = "|cff00ffff|Hfuoconoteway:" .. "2405" .. ":48.85 78.33;49.9 79.3|h[" .. L.navigaTOMTOM .. "]|h|r"
		,
		idzona = 2405,
		drop = { 257446 }
	},
	-- 257446 zona 2405 idquest 93237 object=605169/final-clutch-of-predaxas /way 48.85 78.33 - /way 49.9 79.3

	{
		id = 93341,
		tipo = 1,
		note = "|cff00ffff|Hfuoconoteway:" .. "2405" .. ":64.40 75.52|h[" .. L.navigaTOMTOM .. "]|h|r"
		,
		idzona = 2405,
		drop = { 267139 }
	}, --toy  [Buco Nero Affamato]
	{
		id = 0,
		tipo = 1,
		note = "|cff00ffff|Hfuoconoteway:" .. "2405" .. ":46.92 79.89|h[" .. L.navigaTOMTOM .. "]|h|r"
		,
		idzona = 2405,
		drop = { 250319 }
	}, --toy  [Innesto d'Ombra del Ricercatore]
	{
		id = 0,
		tipo = 1,
		note = "|cff00ffff|Hfuoconoteway:" .. "2405" .. ":38.04 68.83|h[" .. L.navigaTOMTOM .. "]|h|r"
		,
		idzona = 2405,
		drop = { 264303 }
	}, --pet  [Willie]
	{
		id = 0,
		tipo = 1,
		note = "|cff00ffff|Hfuoconoteway:" .. "2405" .. ":65 60|h[" .. L.navigaTOMTOM .. "]|h|r"
		,
		idzona = 2405,
		drop = { 262774 }
	},                                                                     --pet  [Gortham]

	{ tipo = 5,   idzona = 2405, achiID = 62126, drop = { 264695 } },      -- Achievement Tesori della Tempesta del Vuoto - Segnale del Pacchetto Interdimensionale

	{ id = 90962, tipo = 7,      idzona = 2405,  drop = { 257180, 265030 } }, -- from chect 268485

	{
		tipo = 9,
		idzona = 2405,
		drop = { 260696 },
		factionID = 2699,
		renownNeeded = 19,
		valutaID = 3316,
		quantity = 8000,
		npc = 248328
		,
		note = "|cff00ffff|Hfuoconoteway:" .. "2405" .. ":52.5 72.9|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, -- Razza della Tempesta Vincolata dal Vuoto
	{
		tipo = 9,
		idzona = 2405,
		drop = { 257445 },
		factionID = 2699,
		renownNeeded = 17,
		valutaID = 3316,
		quantity = 6000,
		npc = 248328
		,
		note = "|cff00ffff|Hfuoconoteway:" .. "2405" .. ":52.5 72.9|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, -- Lacerartiglio Famelico
	{
		tipo = 9,
		idzona = 2405,
		drop = { 263244 },
		factionID = 2699,
		renownNeeded = 16,
		valutaID = 3316,
		quantity = 4000,
		npc = 248328
		,
		note = "|cff00ffff|Hfuoconoteway:" .. "2405" .. ":52.5 72.9|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, -- Fontana Enigmatica
	{
		tipo = 9,
		idzona = 2405,
		drop = { 263492 },
		factionID = 2699,
		renownNeeded = 14,
		valutaID = 3316,
		quantity = 2500,
		npc = 248328
		,
		note = "|cff00ffff|Hfuoconoteway:" .. "2405" .. ":52.5 72.9|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, -- Scattazecca



	-- Professione: Fishing
	{ tipo = 3,    OggettoDiScambio = 268730, note = L.pesca1 .. "" .. "\n|cff00ffff|Hfuoconoteway:" .. "2444" .. ":50 30|h[" .. L.navigaTOMTOM .. "]|h|r\n", idzona = { 2405, 2444 }, drop = { 260916 },                                                                                                npc = 0 }, -- Nether-Swept Drake - Fishing Voidstorm (Duello del Carnefice)

	-- Professione: LW
	{ tipo = 3,    OggettoDiScambio = 272392, note = L.ritualsite2 , idzona = { 2585, 2594 }, drop = { 270058 },  npc = 0 }, -- Imbracatura di Corda della Lince  siti rituali



	---------------------------------
	---------- Achievement ----------
	---------------------------------


	{ tipo = 5,    achiID = 62386,            drop = { 252011 } }, -- Achievement Illuminare la notte - alapetalo-brillante

	{ tipo = 5,    achiID = 61584,            drop = { 257145 } }, -- Achievement Midnight Glyph Hunter - Crimson Dragonhawk
	{ tipo = 5,    achiID = 61506,            drop = { 246736 } }, -- mount 246736 -- Lincetetra d'Avorio -- quest 95324  achi 61506

	{ tipo = 5,    achiID = 61799,            drop = { 263222 } }, -- {263222} Arcanovoid Construct        - Achievement Delve NEMESIS S1 DA_VERIFICARE se rimosso
	{ tipo = 5,    achiID = 61906,            drop = { 257199 } }, -- {257199} Giganto Manis               - Achievement Glory of the Midnight Delver
	{ tipo = 5,    achiID = 42703,            drop = { 257193 } }, -- {257193} Preyseeker's Nightmare      - Achievement Prey Nightmare Mode III
	{ tipo = 5,    achiID = 61256,            drop = { 262620 } }, -- {262620} Calamitous Carrion          - Achievement Keystone Master S1 DA_VERIFICARE se rimosso
	{ tipo = 5,    achiID = 61258,            drop = { 262621 } }, -- {262621} Convalescent Carrion        - Achievement Keystone Legend S1 DA_VERIFICARE se rimosso
	{ tipo = 5,    achiID = 62385,            drop = { 260697 } }, -- {260697} Lab-grown Stormray          - Achievement Staring Into The Void
	{ tipo = 5,    achiID = 61188,            drop = { 260228 } }, -- {260228} Galactic Gladiator's Gor.   - Achievement PvP Gladiator S1 DA_VERIFICARE se rimosso
	{ tipo = 5,    achiID = 61403,            drop = { 257504 , 257502 } },	-- {257504} Vicious Snaplizard          - PvP Rated Reward Alliance  S1 DA_VERIFICARE se rimosso 	-- {257502} Vicious Snaplizard          - PvP Rated Reward Horde  S1 DA_VERIFICARE se rimosso
	{ tipo = 5,    achiID = 61380,            drop = { 260887 } }, -- {260887} Tenebrous Harrower          - Achievement Glory of the Midnight Raider
	{ tipo = 5,    achiID = 61567,            drop = { 240840 } }, -- affilatino >>  eroe-delle-spedizioni-di-midnight



	-------------------------------
	-- TWW
	{ id = 0,      tipo = 3,                  idzona = 2248,                                                                                                  drop = { 223270 },       quantity = 10,                                                                                                    OggettoDiScambio = 224025 }, -- scheggia crepitante >> alunira

	-- Cartelli di Cavafonda - trove paragon (Undermine) [aggiunti da Forgia]
	{ tipo = 8, idzona = 2346, drop = { 229957 }, factionID = 2673 }, -- DA_AGGIUNTA Bilgewater Bombardier (Cartello degli Acqualorda / Bilgewater)
	{ tipo = 8, idzona = 2346, drop = { 229937 }, factionID = 2675 }, -- DA_AGGIUNTA Blackwater Bonecrusher (Cartello degli Acquanera / Blackwater)
	{ tipo = 8, idzona = 2346, drop = { 229943 }, factionID = 2677 }, -- DA_AGGIUNTA Steamwheedle Supplier (Cartello degli Spargifumo / Steamwheedle)
	{ tipo = 8, idzona = 2346, drop = { 229951 }, factionID = 2671 }, -- DA_AGGIUNTA Venture Co-ordinator (S.P.R. Co. / Venture Company)
	{ tipo = 8, idzona = 2346, drop = { 233064 }, factionID = 2669 }, -- DA_AGGIUNTA Bronze Goblin Waveshredder (Soluzioni Micciascura / Darkfuse Solutions)
	-- Vendor valuta (Undermine S.C.R.A.P.)
	
	{
		tipo = 6,
		valutaID = 3218,
		quantity = "333",
		idzona = 2346,
		drop = { 229949 },
		npc = { 234776 },
		note = "|cff00ffff|Hfuoconoteway:" .. "2346" .. ":25.6 38.6:2:234776|h[" .. L.navigaTOMTOM .. "]|h|r\n"
	}, -- DA_AGGIUNTA Personalized Goblin S.C.R.A.P.per (cassettina 233557)

	-- Rari TWW (drop uccidendo il raro)
	{ id = 0, tipo = 4, idzona = 2371, drop = { 246067 }, npc = 232195, note = "|cff00ffff|Hfuoconoteway:" .. "2371" .. ":70.6 49.4:2:232195|h[" .. L.navigaTOMTOM .. "]|h|r\n" }, -- DA_AGGIUNTA Pearlescent Krolusk <- Urmag (K'aresh)
	{ id = 0, tipo = 4, idzona = 2371, drop = { 246160 }, npc = 234845, note = "|cff00ffff|Hfuoconoteway:" .. "2371" .. ":74 32.4:2:234845|h[" .. L.navigaTOMTOM .. "]|h|r\n" }, -- DA_AGGIUNTA Sthaarbs's Last Lunch <- Sthaarbs (K'aresh)

	-- Void-Scarred (drop da rare nelle Visioni Orripilanti, da Dornogal - idzona 2403/2404)
	{ id = 0, tipo = 4, idzona = 2404, drop = { 235700 }, npc = 237991, note = "|cff00ffff|Hfuoconoteway:" .. "2404" .. ":66.6 71.4:2:237991|h[" .. L.navigaTOMTOM .. "]|h|r\n" }, -- DA_AGGIUNTA Void-Scarred Gryphon
	{ id = 0, tipo = 4, idzona = 2404, drop = { 235705 }, npc = 238079, note = "|cff00ffff|Hfuoconoteway:" .. "2404" .. ":63 37:2:238079|h[" .. L.navigaTOMTOM .. "]|h|r\n" }, -- DA_AGGIUNTA Void-Forged Stallion
	{ id = 0, tipo = 4, idzona = 2403, drop = { 235706 }, npc = 238836, note = "|cff00ffff|Hfuoconoteway:" .. "2403" .. ":60.4 55:2:238836|h[" .. L.navigaTOMTOM .. "]|h|r\n" }, -- DA_AGGIUNTA Void-Scarred Pack Mother (raro: Void-Scarred Wolf)
	{ id = 0, tipo = 4, idzona = 2403, drop = { 235707 }, npc = 238145, note = "|cff00ffff|Hfuoconoteway:" .. "2403" .. ":48.2 53.2:2:238145|h[" .. L.navigaTOMTOM .. "]|h|r\n" }, -- DA_AGGIUNTA Void-Scarred Windrider (raro: Void-Scarred Wyvern Matriarch)



	-------------------------------
	--old
	{ id = 91075,  tipo = 1,                  note = L.successione1,                                                                                          idzona = 2371,           drop = { 245274, 245273, 244916, 244907, 245252, 244909, 245253, 244468, 245215, 244467, 245212, 244914, 242734 } },
	{ id = 223315, tipo = 2,                  idzona = 2215,                                                                                                  drop = { 223315 },       npc = 207802 }, --Prole di Beledar
	{ id = 223501, tipo = 2,                  idzona = 2214,                                                                                                  drop = { 223501 },       npc = 220285 }, --Lurker
	{ id = 229953, tipo = 2,                  idzona = 2346,                                                                                                  drop = { 229953 },       npc = 234621 }, --Spazzatura del Gallagio
	--    {id = 53000, tipo=2,idzona = 864, drop = {174842}, npc=138794},  --vol'dun id wq 52196 - kill 53000
	{ id = 52196,  tipo = 7,                  idzona = 864,                                                                                                   drop = { 174842 },       npc = 138794 }, --vol'dun id wq 52196 - kill 53000
	{ id = 37464,  tipo = 2,                  idzona = 542,                                                                                                   drop = { 116771 },       npc = 83746 }, --guglie di arak - rukhmar

	{ id = 32099,  tipo = 2,                  idzona = 379,                                                                                                   drop = { 87771 },        npc = 60491 }, --sha della rabia
	{ id = 32098,  tipo = 2,                  idzona = 376,                                                                                                   drop = { 89783 },        npc = 62346 }, --brigata di sal
	{ id = 32518,  tipo = 2,                  idzona = 504,                                                                                                   drop = { 95057 },        npc = 69099 }, --nalak
	{ id = 32519,  tipo = 2,                  idzona = 507,                                                                                                   drop = { 94228 },        npc = 69161 }, --undasta
}

-- non più ottenibile!
-- non più ottenibile!
--	{id = 0, tipo=5, achiID=42300, drop = {246594} },-- {246594} Light-Forged Mechsuit       - Achievement Pre-Patch Two Minutes to Midnight
-- {224148} Retrained Skyrazor          - Vendor Materialist Ophinell (npc=249196) Pre-Patch

----------------------------------------------------
-- lista BOSS da fare
----------------------------------------------------
-- statID >> StatNameCacheBuilt
local droplist = {
	-- {EJID (dungeon id; cercare su journalinstalce), bossIndex, difficultyID, dropIDs}
	-- difficolta 17 lfr, 14 normal, 15 heroic, 16 mythic, 23 mythic+, 233 raid mitico 15 flex
	-- cercare il boss in journalEncounter
	
	-- Midnight

	-- Sporefall 12.0.7
		-- la mount di prende con 5x https://www.wowhead.com/item=269245/delicious-sporesnack
	{ 1305, 1, {17,14, 15, 233}, {264367, 264313, 269240, 268280}, statID = { 63233, 63234, 63235, 63236 } },

	-- Midnight Falls
	{ 1308, 2, 16,                 { 246590 },                 statID = { 61307 } }, --Ashes of Belo'ren - Midnight Falls (Mythic)

	-- Magisters' Terrace M+
	{ 1300, 4, 23,                 { 260231 },                 statID = { 61217 } }, --Lucent Hawkstrider - Zampalesta Lucente - Degentrius encounterID=3074, DA_VERIFICARE solo S1 ?
	{ 1299, 4, 23,                 { 262914 },                 statID = { 41295 } }, -- Zampalesta Spettrale - Cuore Irrequieto encounterID=3059, DA_VERIFICARE solo S1 ?

	-- TWW Manaforgia Omega
	{ 1302, 8, 16,                 { 243061 },                 statID = { 41664 } }, --Mangiastelle Svincolato

	-- TWW Liberazione di Cavafonda
	{ 1296, 8, { 17, 14, 15, 16 }, { 236960 },                 statID = { 41327, 41328, 41329, 41330 } }, --Prototipo A.S.M.R.
	{ 1296, 8, 16,                 { 235626 },                 statID = { 41330 } },               --big g

	-- TWW Palazzo dei Nerub'ar
	{ 1273, 8, { 17, 14, 15, 16 }, { 224147 },                 statID = { 40295, 40296, 40297, 40298 } }, --Redini dello Sferzacieli Sureki
	{ 1273, 8, 16,                 { 224151 },                 statID = { 40298 } },               --Redini dello Sferzacieli Asceso

	-- TWW Faglia di Fiammoscura
	{ 1210, 4, 23,                 { 225548 },                 statID = { 20484 } }, --Guinzaglio di Miccia
	-- TWW Volta di pietra
	{ 1269, 4, 23,                 { 226683 },                 statID = { 40722 } }, --Meccanotuta Malfunzionante

	-- DF raid: Amirdrassil
	{ 1207, 8, 16,                 { 211280 },                 statID = { 19385 } }, --Piuma druido
	{ 1207, 9, 16,                 { 210061, 207729, 207728 }, statID = 19386 }, --Amirdrassil - Mount: Anu'relos encounterID=2677,
	-- Fyrakk -> mount + 2 versioni di Fyr'alath

	-- DF dungeon / megadungeon
	{ 1209, 8, 23, { 208216, -- questo e' l'offetto che usato da le mount seguenti:
		68823, 186638, 13335, 181819, 168826, 142236, 159921, 44151, 63040, 32768, 63043, 159842, 35513, 68824, 160829
	} },                     -- mount quantico - Alba degli Infiniti - Deios (M+) ,  statID=16097 >> e' errato !!! e' di uldaman

	-- Shadowlands
	{ 1193, 3,  { 17, 14, 15, 16 }, { 186656 },               statID = { 15144, 15145, 15146, 15147 } }, -- Sanctum - Redini del Destriero Tenebroso del Sanctum
	{ 1193, 10, 16,                 { 186642 },               statID = { 15176 } },             -- Sanctum del Dominio - Silvanas
	{ 1195, 11, 16,                 { 190768 },               statID = { 15467 } },             -- Sepolcro dei Primi - Carceriere
	{ 1182, 4,  23,                 { 181819 },               statID = { 15168 } },             -- Meccaliante del Maestro del Cartello

	-- BFA
	{ 1176, 9,  16,                 { 166705 } }, -- Jaina --Battaglia di Dazar'alor - Jaina M
	{ 1176, 9,  17,                 { 166518 } }, -- Jaina --mimmog - Jaina M
	{ 1176, 7,  { 17, 14, 15, 16 }, { 166518 } }, -- Jaina --mimmog - Jaina M
	{ 1180, 12, 16,                 { 174872 } }, -- N'zoth - Ny'alotha - N'zoth M
	{ 1022, 4,  23,                 { 160829 } }, --Grottamarcia - Abominio (M+)
	{ 1041, 4,  23,                 { 159921 } }, --Requie dei Re - Re Dazar (M+)
	{ 1178, 8,  23,                 { 169378 } }, --Operazione: Meccagon
	{ 1178, 4,  23,                 { 168826 } }, --Operazione: Meccagon - pacificatore HK-8
	{ 1001, 4,  23,                 { 159842 } }, --covo della libertà

	-- legion
	{ 946,  11, 16,                 { 152789 } }, --Antorus - Argus M
	{ 946,  2,  { 17, 14, 15, 16 }, { 152816 } }, -- Antorus Mastino Ardente degli Antoran
	{ 875,  5,  { 17, 14, 15, 16 }, { 143643 } }, ---Antorus verme dell'abiso
	{ 860,  4,  23,                 { 142236 } }, --Ritorno a Karazhan - Mezzanotte il ritorno (M+)
	{ 860,  6,  23,                 { 138798 } }, --Ritorno a Karazhan - Illusione: fuoco solare (M+)
	{ 860,  9,  23,                 { 142552 } }, --Ritorno a Karazhan - Dragone delle Braci Infuocato (M+)
	{ 786,  10, { 17, 14, 15, 16 }, { 137574 } }, --Rocca della Notte - Gul'dan N
	{ 786,  10, 16,                 { 137575 } }, --Rocca della Notte - Gul'dan M

	-- draenor
	{ 669,  13, 16,                 { 123890 } }, --Cittadella del Fuoco Infernale - Archimonde M
	{ 669,  5,  { 17, 14, 15, 16 }, { 138808 } }, --illusione
	{ 477,  1,  { 17, 14, 15, 16 }, { 138807 } }, --illusione
	{ 477,  3,  { 17, 14, 15, 16 }, { 138835 } }, --illusione --> tectus 3 o 4 ?!?!?!
	{ 537,  4,  { 17, 14, 15, 16 }, { 138806 } }, --illusione
	{ 457,  10, 16,                 { 116660 } }, --Fonderia dei Roccianera - Manonera M
	{ 457,  10, { 17, 14, 15, 16 }, { 138809 } }, --Fonderia dei Roccianera - illusione


	-- pandaria
	{ 369,  14, 16,                 { 104253 } },       --Assedio di Orgrimmar - Garrosh M
	{ 362,  2,  { 17, 14, 15, 16 }, { 93666, 94574 } }, --regno del tuono
	{ 362,  6,  { 17, 14, 15, 16 }, { 95059, 94835 } }, --regno del tuono
	{ 362,  8,  { 17, 14, 15, 16 }, { 97960 } },        --regno del tuono primordius
	{ 362,  9,  { 17, 14, 15, 16 }, { 94152 } },        --regno del tuono anious
	{ 320,  2,  { 17, 14, 15, 16 }, { 167051 } },       --terrazza
	{ 320,  3,  { 17, 14, 15, 16 }, { 167052 } },       --terrazza
	{ 320,  4,  { 17, 14, 15, 16 }, { 138805 } },       --terrazza ?illu
	{ 330,  1,  { 17, 14, 15, 16 }, { 167058 } },       --cuore pet
	{ 330,  2,  { 17, 14, 15, 16 }, { 167053 } },       --cuore pet
	{ 330,  3,  { 17, 14, 15, 16 }, { 167054 } },       --cuore pet
	{ 330,  5,  { 17, 14, 15, 16 }, { 167055 } },       --cuore pet
	{ 330,  6,  { 17, 14, 15, 16 }, { 167056 } },       --cuore pet
	{ 317,  6,  { 17, 14, 15, 16 }, { 138804 } },       --segrete illu
	{ 317,  5,  { 17, 14, 15, 16 }, { 87777 } },        --segrete mount
	{ 317,  1,  { 17, 14, 15, 16 }, { 167047 } },       --segrete pet
	{ 317,  3,  { 17, 14, 15, 16 }, { 167048 } },       --segrete pet
	{ 317,  5,  { 17, 14, 15, 16 }, { 167049 } },       --segrete pet
	{ 317,  6,  { 17, 14, 15, 16 }, { 167050 } },       --segrete pet

	--Cataclysm
	--Anima del Drago
	{ 187,  5,  0,                  { 152979 } },          --pet
	{ 187,  5,  0,                  { 78919 } },           --mount Ultraxion
	{ 187,  7,  0,                  { 152980 } },          --pet
	{ 187,  8,  0,                  { 77069, 77067, 152981 } }, --mount Alamorte x2 pet

	--Terre del Fuoco
	{ 78,   1,  0,                  { 152976 } }, -- pet
	{ 78,   3,  0,                  { 71665 } }, -- mount alis
	{ 78,   4,  0,                  { 152975 } }, -- pet
	{ 78,   5,  0,                  { 152977 } }, -- pet
	{ 78,   6,  0,                  { 152978 } }, -- pet
	{ 78,   7,  0,                  { 69224 } }, -- mount Ragnaros

	--Trono dei Quattro Venti
	{ 74,   1,  0,                  { 152974 } },           -- pet
	{ 74,   2,  0,                  { 63041, 152973, 138836 } }, -- mount + pet

	--Sotterranei dell'Ala Nera
	{ 73,   1,  0,                  { 152966 } },    -- pet
	{ 73,   5,  0,                  { 152967 } },    -- pet
	{ 73,   6,  0,                  { 152968, 138802 } }, -- pet + ill

	-- Bastione del Crepuscolo
	{ 72,   2,  0,                  { 152969 } }, -- pet
	{ 72,   3,  0,                  { 152970 } }, -- pet
	{ 72,   4,  0,                  { 152972 } }, -- pet

	--Zul'gurub
	{ 76,   2,  2,                  { 68823 } }, --Zul'gurub - Raptor Razzashi Corazzato (HC)
	{ 76,   7,  2,                  { 68824 } }, --Zul'gurub - Pantera Zuliana (HC)

	--Pinnacolo del Vortice
	{ 68,   2,  0,                  { 63040 } },

	--Nucleo di Pietra
	{ 67,   2,  0,                  { 63043 } },

	-- WTLK
	-- Occhio dell'Eternità
	{ 756,  1,  { 3, 4 },           { 43953, 43952 } }, -- mount

	--Rocca della Corona di Ghiaccio
	{ 758,  12, 6,                  { 50818 } },     -- invincibile
	{ 758,  12, { 5, 6 },           { 142099, 138955 } }, -- mascotte + ill
	{ 758,  12, { 3, 4 },           { 142098, 138955 } }, -- mascotte + ill
	{ 758,  1,  { 3, 4, 5, 6 },     { 142094 } },    -- pet
	{ 758,  4,  { 3, 4, 5, 6 },     { 142095 } },    -- pet
	{ 758,  7,  { 3, 4, 5, 6 },     { 142096 } },    -- pet
	{ 758,  11, { 3, 4, 5, 6 },     { 142097 } },    -- pet

	--Ulduar
	{ 759,  13, 14,                 { 45693, 142093, 138801 } }, -- mount testa , per , ill
	{ 759,  2,  14,                 { 142086 } },           -- pet
	{ 759,  3,  14,                 { 142087 } },           -- pet
	{ 759,  5,  14,                 { 142088 } },           -- pet
	{ 759,  7,  14,                 { 142089 } },           -- pet
	{ 759,  8,  14,                 { 142090, 138800 } },   -- pet + illu
	{ 759,  9,  14,                 { 138800 } },           -- illu
	{ 759,  10, 14,                 { 142091 } },           -- pet
	{ 759,  11, 14,                 { 138800, 142092 } },   -- illu + pet

	--Ordalia dei Crociati
	{ 757,  1,  { 3, 4, 5, 6 },     { 142083, 142084 } }, -- pet
	{ 757,  5,  { 3, 4, 5, 6 },     { 142085 } },     -- pet

	--Antro di Onyxia
	{ 760,  1,  { 3, 4, 5, 6 },     { 49636 } }, -- mount

	--Santuario di Ossidiana
	{ 755,  1,  3,                  { 43986 } }, -- mount
	{ 755,  1,  4,                  { 43954 } }, -- mount

	-- Naxxramas
	{ 754,  3,  { 3, 4 },           { 93030 } }, -- pet
	{ 754,  6,  { 3, 4 },           { 93032 } }, -- pet
	{ 754,  12, { 3, 4 },           { 93029 } }, -- pet

	-- Volta di Archavon
	{ 753,  1,  { 3, 4 },           { 43959 } }, -- mount
	{ 753,  2,  { 3, 4 },           { 43959 } }, -- mount
	{ 753,  3,  { 3, 4 },           { 43959 } }, -- mount
	{ 753,  4,  { 3, 4 },           { 43959 } }, -- mount

	-- Pinnacolo di Utgarde
	{ 286,  3,  2,                  { 44151 } }, -- mount

	--Burning Crusade
	--Occhio della Tempesta
	{ 749,  4,  4,                  { 32458 } }, -- mount

	-- Karazhan
	{ 745,  2,  3,                  { 30480 } }, -- mount

	-- Terrazza dei Magisteri
	{ 249,  4,  2,                  { 35513, 35275 } }, -- mount + toy

	-- Sale dei Sethekk
	{ 252,  2,  2,                  { 32768 }, diff=2 }, -- mount -- 115

	--vanilla
	-- Stratholme - Ingresso di Servizio
	{ 1292, 6,  1,                  { 13335 } }, -- mount


	{ 751,  9,  14,                 { 32837, 32838 },         achiID = 426 }, --Tempio Nero - Illidan (classico, warglaives)

}

local function FuocoGetItemIcon(itemID)
	local item = Item:CreateFromItemID(itemID)

	if item:IsItemDataCached() then
		return item:GetItemIcon()
	end

--	TuttiILinkSonoCaricati = false
--	item:ContinueOnItemLoad(function()
--		ScheduleUpdate()
--	end)

	return nil
end

local FuocoNoteFont = CreateFont("FuocoNoteFont")
FuocoNoteFont:SetFont("Interface\\AddOns\\FuocoNote\\Fonts\\NotoSansJP-Bold.ttf", 12, "")

FuocoNoteDB = FuocoNoteDB or {}

-- Escapa i caratteri speciali HTML nei testi dinamici dal gioco (nomi fazione/npc)
-- prima di inserirli nel SimpleHTML (es. "S.P.R. & Co." rompe il parsing). '&' per primo.
local function EscapeHTML(s)
	if s == nil then return s end
	s = tostring(s)
	s = s:gsub("&", "&amp;")
	s = s:gsub("<", "&lt;")
	s = s:gsub(">", "&gt;")
	return s
end
local function ToSimpleHTMLLeft(text)
	text = tostring(text or "")
	text = text:gsub("\n", "<br/>")
	return "<html><body><p align=\"left\">" .. text .. "</p></body></html>"
end

local function ToSimpleHTML_Full(content)
	return "<html><body>" .. content .. "</body></html>"
end

----------------------------------------------------
-- Pannello opzioni (Settings API nuova)
----------------------------------------------------
local fuoconoteCategoryID

local function fuoconoteCreateOptionsPanel()
	local panel = CreateFrame("Frame", addonName .. "OptionsPanel", UIParent)
	panel.name = addonName

	local title = panel:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
	title:SetPoint("TOPLEFT", 16, -16)
	title:SetText(addonName)

	local desc = panel:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
	desc:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -8)
	desc:SetWidth(400)
	desc:SetText(L.SettingDescText)

	-- Mostra/nascondi (1sx)
	local chkShowMain = CreateFrame("CheckButton", addonName .. "ShowMainCheck", panel,
		"InterfaceOptionsCheckButtonTemplate")
	chkShowMain:SetPoint("TOPLEFT", desc, "BOTTOMLEFT", 0, -12)
	chkShowMain.Text:SetText(L.Setting1)
	chkShowMain:SetScript("OnClick", function(self)
		if not db then return end
		db.ShowMain = self:GetChecked() and true or false
		if db.ShowMain then
			if mainFrame and not mainFrame:IsShown() then
				mainFrame:Show()
				UpdateText()
			end
		else
			if mainFrame and mainFrame:IsShown() then mainFrame:Hide() end
		end
	end)

	-- Quest all (1dx)
	local chkQuestAll = CreateFrame("CheckButton", addonName .. "QuestAllCheck", panel,
		"InterfaceOptionsCheckButtonTemplate")
	chkQuestAll:SetPoint("TOPLEFT", chkShowMain, "TOPRIGHT", 250, 0)
	chkQuestAll.Text:SetText(L.Setting2)
	chkQuestAll:SetScript("OnClick", function(self)
		if not db then return end
		db.MostraQuestFatte = self:GetChecked() and true or false
		UpdateText()
	end)

	-- Boss all (2sx)
	local chkBossAll = CreateFrame("CheckButton", addonName .. "BossAllCheck", panel,
		"InterfaceOptionsCheckButtonTemplate")
	chkBossAll:SetPoint("TOPLEFT", chkShowMain, "BOTTOMLEFT", 0, -8)
	chkBossAll.Text:SetText(L.Setting3)
	chkBossAll:SetScript("OnClick", function(self)
		if not db then return end
		db.MostraBossOggettiFatti = self:GetChecked() and true or false
		UpdateText()
	end)

	-- DropKnown (2dx)
	local chkDropKnown = CreateFrame("CheckButton", addonName .. "DropKnownCheck", panel,
		"InterfaceOptionsCheckButtonTemplate")
	chkDropKnown:SetPoint("TOPLEFT", chkQuestAll, "BOTTOMLEFT", 0, -8)
	chkDropKnown.Text:SetText(L.Setting6)
	chkDropKnown:SetScript("OnClick", function(self)
		if not db then return end
		db.MostraDropKnown = self:GetChecked() and true or false
		UpdateText()
	end)

	-- Conosciuti show (3sx)
	local chkConosciutiShow = CreateFrame("CheckButton", addonName .. "ConosciutiShowCheck", panel,
		"InterfaceOptionsCheckButtonTemplate")
	chkConosciutiShow:SetPoint("TOPLEFT", chkBossAll, "BOTTOMLEFT", 0, -8)
	chkConosciutiShow.Text:SetText(L.Setting5)
	chkConosciutiShow:SetScript("OnClick", function(self)
		if not db then return end
		db.BossDiCuiHoTuttoShow = self:GetChecked() and true or false
		UpdateText()
	end)

	-- HideInCombat  3dx (destra di chkConosciutiShow, sotto chkDropKnown)
	local chkHideInCombat = CreateFrame("CheckButton", addonName .. "HideInCombatCheck", panel,
		"InterfaceOptionsCheckButtonTemplate")
	chkHideInCombat:SetPoint("TOPLEFT", chkDropKnown, "BOTTOMLEFT", 0, -8)
	chkHideInCombat.Text:SetText(L.Setting7)
	chkHideInCombat:SetScript("OnClick", function(self)
		if not db then return end
		db.HideInCombat = self:GetChecked() and true or false
	end)

	-- SayGZ (3dx)
	--		local chkSayGZ = CreateFrame("CheckButton", addonName.."SayGZCheck", panel, "InterfaceOptionsCheckButtonTemplate")
	--		chkSayGZ:SetPoint("TOPLEFT", chkDropKnown, "BOTTOMLEFT", 0, -8)
	--		chkSayGZ.Text:SetText(L.Setting10)
	--		chkSayGZ:SetScript("OnClick", function(self)
	--		    if not db then return end
	--		    db.SayGZ = self:GetChecked() and true or false
	--		    UpdateText()
	--		end)

	-- ── Sezione filtri tipo ──────────────────────────────────────────
	local filterLabel = panel:CreateFontString(nil, "ARTWORK", "GameFontNormal")
	filterLabel:SetPoint("TOPLEFT", chkHideInCombat, "BOTTOMLEFT", 0, -16)
	filterLabel:SetText(L.FilterSectionLabel)

	local function makeFilterCheck(name, key, anchor, labelText)
		local chk = CreateFrame("CheckButton", addonName .. name, panel, "InterfaceOptionsCheckButtonTemplate")
		chk:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", 0, -4)
		chk.Text:SetText(labelText)
		chk:SetScript("OnClick", function(self)
			if not db then return end
			db[key] = self:GetChecked() and true or false
			UpdateText()
		end)
		return chk
	end

	local chkHidePet      = makeFilterCheck("HidePet", "HidePet", filterLabel, L.HidePet)
	local chkHideMount    = makeFilterCheck("HideMount", "HideMount", chkHidePet, L.HideMount)
	local chkHideToy      = makeFilterCheck("HideToy", "HideToy", chkHideMount, L.HideToy)
	local chkHideIllusion = makeFilterCheck("HideIllusion", "HideIllusion", chkHideToy, L.HideIllusion)
	local chkHideTransmog = makeFilterCheck("HideTransmog", "HideTransmog", chkHideIllusion, L.HideTransmog)

	-- Slider opacità finestra (4sx)
	local sliderAlpha     = CreateFrame("Slider", addonName .. "AlphaSlider", panel, "OptionsSliderTemplate")
	sliderAlpha:SetPoint("TOPLEFT", chkConosciutiShow, "BOTTOMLEFT", 0, -24)
	sliderAlpha:SetMinMaxValues(0.1, 1.0)
	sliderAlpha:SetValueStep(0.05)
	sliderAlpha:SetObeyStepOnDrag(true)

	_G[sliderAlpha:GetName() .. "Low"]:SetText("10%")
	_G[sliderAlpha:GetName() .. "High"]:SetText("100%")
	_G[sliderAlpha:GetName() .. "Text"]:SetText(L.Setting9)

	sliderAlpha:SetScript("OnValueChanged", function(self, value)
		if not db then return end
		db.FrameAlpha = value
		if mainFrame and not mainFrame:IsMouseOver() then
			mainFrame:SetAlpha(value)
		end
	end)

	local logo = panel:CreateTexture(nil, "ARTWORK")
	logo:SetSize(256, 256)
	logo:SetTexture("Interface\\AddOns\\" .. addonName .. "\\logo256x256.png")
	logo:SetPoint("TOP", sliderAlpha, "BOTTOM", 50, -40)

	-- Refresh quando apri il pannello
	panel:SetScript("OnShow", function()
		if not db then return end
		chkShowMain:SetChecked(db.ShowMain and true or false)
		chkQuestAll:SetChecked(db.MostraQuestFatte and true or false)
		chkBossAll:SetChecked(db.MostraBossOggettiFatti and true or false)
		chkConosciutiShow:SetChecked(db.BossDiCuiHoTuttoShow and true or false)
		chkDropKnown:SetChecked(db.MostraDropKnown and true or false)
		chkHideInCombat:SetChecked(db.HideInCombat and true or false)
		chkHidePet:SetChecked(db.HidePet and true or false)
		chkHideMount:SetChecked(db.HideMount and true or false)
		chkHideToy:SetChecked(db.HideToy and true or false)
		chkHideIllusion:SetChecked(db.HideIllusion and true or false)
		chkHideTransmog:SetChecked(db.HideTransmog and true or false)
		--		    chkSayGZ:SetChecked(db.SayGZ and true or false)
		sliderAlpha:SetValue(db.FrameAlpha or 0.6)
	end)


	-- Registrazione nel nuovo Settings
	local category = Settings.RegisterCanvasLayoutCategory(panel, addonName)
	Settings.RegisterAddOnCategory(category)
	fuoconoteCategoryID = category:GetID()
end

----------------------------------------------------
-- Mappa EJID
----------------------------------------------------
local EJNameByID = {}
local EJExpByID  = {}

--Se ti capita che EJ_GetTierInfo/EJ_GetNumTiers siano nil, carica l’UI dell’Encounter Journal prima di buildare
--if C_AddOns and C_AddOns.LoadAddOn then
--  C_AddOns.LoadAddOn("Blizzard_EncounterJournal")
--else
--  LoadAddOn("Blizzard_EncounterJournal")
--end

local function fuoconoteBuildEJNameByID()
	if not EJ_GetNumTiers or not EJ_GetInstanceByIndex or not EJ_SelectTier or not EJ_GetTierInfo then return end

	wipe(EJNameByID)
	wipe(EJExpByID)

	local numTiers = EJ_GetNumTiers()
	for tier = 1, numTiers do
		EJ_SelectTier(tier)
		local expName = EJ_GetTierInfo(tier) or ("Tier " .. tier) -- nome espansione

		local function Scan(isRaid)
			local idx = 1
			while true do
				local journalInstanceID, name = EJ_GetInstanceByIndex(idx, isRaid) -- isRaid=true raid, false dungeon
				if not journalInstanceID then break end
				EJNameByID[journalInstanceID] = name
				EJExpByID[journalInstanceID]  = expName
				idx                           = idx + 1
			end
		end

		Scan(true)
		Scan(false)
	end
end


local function FindSavedInstanceByEJ(journalInstanceID, difficultyID)
	local targetName = EJNameByID[journalInstanceID]
	local expansion = EJExpByID[journalInstanceID]
	if not targetName then
		return nil
	end

	local num = GetNumSavedInstances()
	for i = 1, num do
		local name, id, reset, difficulty, locked, extended,
		instanceIDMostSig, isRaid, maxPlayers, difficultyName,
		numEncounters, encounterProgress = GetSavedInstanceInfo(i)

		if locked and difficulty == difficultyID and name == targetName then
			return {
				index          = i,
				name           = name,
				difficultyName = difficultyName,
				numEncounters  = numEncounters or 0,
				espansione     = expansion or "unknow"
			}
		end
	end
	return nil
end

local function fuoconoteBuildEJBossCache()
    if not EJ_GetEncounterInfoByIndex or not EJ_GetInstanceInfo then return end
    wipe(EJBossCache)
-- difficultyID - diff=
--
-- promemoria: in caso di diff multiple salvare in cache diff >100000 ma fare la query con -100000
--
--| ID | Difficoltà             |
--| 1  | Normal (Dungeon 5-man) |
--| 2  | Heroic (Dungeon)       |
--| 8  | Mythic (Dungeon)       |
--| 14 | Normal (Raid)          |
--| 15 | Heroic (Raid)          |
--| 16 | Mythic (Raid)          |
--| 17 | LFR                    |
--| 233| Mythic (Raid) 15 Flex  |

    for _, item1 in ipairs(droplist) do
        local ejID    = item1[1]
        local bossPos = item1[2]
        local diff = item1.diff or 14

		EJ_SetDifficulty(diff)

		if not EJBossCache[ejID] then
            EJBossCache[ejID] = {}
        end

        if not EJBossCache[ejID][bossPos] then
            local ok = pcall(EJ_SelectInstance, ejID)
            if ok then
                local instanceName = EJ_GetInstanceInfo(ejID)
                local bossName     = EJ_GetEncounterInfoByIndex(bossPos, ejID)

                if instanceName and bossName then
                    EJBossCache[ejID][bossPos] = {
                        instance = instanceName,
                        boss     = bossName,
                    }
                end
            end
        end
    end
end

local function FuocoNoteGetInstanceAndBossNameFromEJ(journalInstanceID, bossPos)
    -- Prima controlla la cache
    local cached = EJBossCache[journalInstanceID]
    if cached and cached[bossPos] then
        return cached[bossPos].instance, cached[bossPos].boss
    end

    -- Fallback con protezione da journalInstanceID inesistente
    if not EJ_GetEncounterInfoByIndex or not EJ_GetInstanceInfo then
        return nil, nil
    end

    -- pcall protegge da errori se l'istanza non esiste nel client attuale
    local ok = pcall(EJ_SelectInstance, journalInstanceID)
    if not ok then
        -- journalInstanceID non esiste (espansione futura o non caricata)
        return nil, nil
    end

    local instanceName = EJ_GetInstanceInfo(journalInstanceID)
    local bossName     = EJ_GetEncounterInfoByIndex(bossPos, journalInstanceID)

    return instanceName, bossName
end


local function fuoconoteIsIllusionCollectedFromItem(itemID)
	itemID = tonumber(itemID)
	if not itemID then return false end
	if not (C_TransmogCollection and C_TransmogCollection.GetIllusionInfo) then
		return false
	end

	local illusionID = IllusionIDByItemID[itemID]
	if not illusionID then
		return false -- item non mappato
	end

	local info = C_TransmogCollection.GetIllusionInfo(illusionID)
	if type(info) ~= "table" then
		return false
	end

	-- in genere: info.name, info.icon, info.isCollected, ecc.
	return info.isCollected == true
end

local function fuoconoteIsAchievementCompleted(achievementID)
	if not achievementID or type(achievementID) ~= "number" then
		return false
	end

	local name, _, _, completed = GetAchievementInfo(achievementID)

	return completed == true
end

local function fuoconoteGetAchievementLink(achievementID)
	if not achievementID or type(achievementID) ~= "number" then
		return nil
	end

	-- GetAchievementLink restituisce il link completo |c...|h[Nome]|h|r
	local link = GetAchievementLink(achievementID)

	return link
end

-- Ritorna: "mount", "toy", "pet", "illusion", "transmog", o nil
local function fuoconoteGetCollectibleTypeRaw(itemID)
	itemID = tonumber(itemID)
	if not itemID then return nil end

	-- Mount
	if C_MountJournal and C_MountJournal.GetMountFromItem then
		local mountID = C_MountJournal.GetMountFromItem(itemID)
		if itemID == 226683 then mountID = 2119 end -- volta di pietra (fix manuale)
		if mountID then return "mount" end
	end

	-- Toy
	if C_ToyBox and PlayerHasToy then
		-- PlayerHasToy non dice se è un toy, ma C_ToyBox.GetToyInfo sì
		if C_ToyBox.GetToyInfo and select(1, C_ToyBox.GetToyInfo(itemID)) ~= nil then
			return "toy"
		end
	end

	-- Pet
	if C_PetJournal and C_PetJournal.GetPetInfoByItemID then
		local speciesID = select(13, C_PetJournal.GetPetInfoByItemID(itemID))
		if speciesID then return "pet" end
	end

	-- Illusione
	if IllusionIDByItemID[itemID] then return "illusion" end

	-- Transmog (fallback)
	if C_TransmogCollection and C_TransmogCollection.PlayerHasTransmog then
		-- Non possiamo sapere se È un transmog senza provarlo;
		-- usiamo il fatto che GetAppearanceByItemID esiste
		if C_TransmogCollection.GetAppearanceByItemID then
			local appearanceID = C_TransmogCollection.GetAppearanceByItemID(itemID)
			if appearanceID then return "transmog" end
		end
	end

	return nil -- tipo non identificato
end

local function fuoconoteGetCollectibleType(itemID)
	itemID = tonumber(itemID)
	if not itemID then return nil end

	local cached = CollectibleTypeCache[itemID]
	if cached ~= nil then
		return cached or nil
	end

	local result = fuoconoteGetCollectibleTypeRaw(itemID)
	if result then
		CollectibleTypeCache[itemID] = result
		return result
	end

	-- Item non ancora caricato: richiedi il caricamento
	-- senza registrare eventi globali
	C_Item.RequestLoadItemDataByID(itemID)
	-- nil = "dati non ancora disponibili, riprova dopo"
	return nil
end

-- Ritorna true se l'item va NASCOSTO secondo i filtri utente
local function fuoconoteIsHiddenByFilter(itemID)
	if not db then return false end
	local tipo = fuoconoteGetCollectibleType(itemID)
	if tipo == "mount" and db.HideMount then return true end
	if tipo == "toy" and db.HideToy then return true end
	if tipo == "pet" and db.HidePet then return true end
	if tipo == "illusion" and db.HideIllusion then return true end
	if tipo == "transmog" and db.HideTransmog then return true end
	return false
end

-- Ritorna true/false; nil = non determinabile (API non pronta o item non mappabile)
local function fuoconoteIsCollectibleOwned(itemID)
	itemID = tonumber(itemID)
	if not itemID then return false end

	-- Mount da item
	if C_MountJournal and C_MountJournal.GetMountFromItem and C_MountJournal.GetMountInfoByID then
		local mountID = C_MountJournal.GetMountFromItem(itemID)
		if (itemID == 226683) then mountID = 2119 end --volta di pietra
		if mountID then
			local _, _, _, _, _, _, _, _, _, _, isCollected = C_MountJournal.GetMountInfoByID(mountID)
			return isCollected == true
		end
	end

	if C_ToyBox and PlayerHasToy then
		if PlayerHasToy(itemID) then
			return true
		end
	end
	-- Pet da item
	if C_PetJournal and C_PetJournal.GetPetInfoByItemID and C_PetJournal.GetNumCollectedInfo then
		itemID = tonumber(itemID)
		if not itemID then return false end

		local speciesID = select(13, C_PetJournal.GetPetInfoByItemID(itemID))           -- 13° return = speciesID [page:1]
		if speciesID then
			local numCollected = select(1, C_PetJournal.GetNumCollectedInfo(speciesID)) -- numCollected, limit [page:0]
			return (numCollected or 0) > 0
		end
	end

	-- Illusione
	if fuoconoteIsIllusionCollectedFromItem(itemID) then
		return true
	end

	-- Aspetto transmog da item (best-effort)
	if C_TransmogCollection and C_TransmogCollection.PlayerHasTransmog then
		return C_TransmogCollection.PlayerHasTransmog(itemID) == true
	end

	return false
end

local function FuocoGetItemInfo(itemID)
	local name, link, quality, iLevel, reqLevel, class, subclass,
	maxStack, equipSlot, iconPath, vendorPrice

	local getter = (C_Item and C_Item.GetItemInfo) -- or GetItemInfo

	name, link, quality, iLevel, reqLevel, class, subclass,
	maxStack, equipSlot, iconPath, vendorPrice = getter(itemID)

	if not link then
		TuttiILinkSonoCaricati = false

		if Item and Item.CreateFromItemID then
			local itemObj = Item:CreateFromItemID(itemID)
			itemObj:ContinueOnItemLoad(function()
				ScheduleUpdate()
			end)
		else
			ScheduleUpdate()
		end
	end

	-- Escapa nome/link: un item col '&' nel nome romperebbe il SimpleHTML
	name = EscapeHTML(name)
	link = EscapeHTML(link)

	return name, link, quality, iLevel, reqLevel, class, subclass,
		maxStack, equipSlot, iconPath, vendorPrice
end

local function IsInArray(arr, value)
	for _, id in ipairs(arr) do
		if id == value then return true end
	end
	return false
end
local function FuocoNoteGetDropLinks(dropIDs)
	db.MostraDropKnown = db.MostraDropKnown or false

	if not dropIDs or #dropIDs == 0 then
		return "", true
	end

	local parts = {}
	local fyralathArr = { 207729, 207728 } -- Fyr'alath
	local quanticoArr = { 68823, 186638, 13335, 181819, 168826, 142236, 159921, 44151, 63040, 32768, 63043, 159842, 35513, 68824, 160829 }

	for _, itemID in ipairs(dropIDs) do
		if type(itemID) == "number" then
			local posseduto = fuoconoteIsCollectibleOwned(itemID)

			if IsInArray(fyralathArr, itemID) then
				for _, id in ipairs(fyralathArr) do --deve averne almeno 1 per ignorare
					posseduto = false
					posseduto = posseduto or fuoconoteIsCollectibleOwned(id)
				end
			end


			if itemID == 211280 then --piuma tindral druido
				posseduto = C_QuestLog.IsQuestFlaggedCompleted(78525) == true
				--return IsSpellKnown(tonumber(spellID) or 0) == true
			end

			if itemID == 208216 then                --Reins of the Quantum Courser
				for _, id in ipairs(quanticoArr) do --deve averli tutti per ignorare
					posseduto = true
					posseduto = posseduto and fuoconoteIsCollectibleOwned(id)
				end
			end


			if not posseduto and itemID ~= 207729 then
				missingDropCount = missingDropCount + 1
			end

			if (db.MostraDropKnown or not posseduto) and (not fuoconoteIsHiddenByFilter(itemID)) and itemID ~= 207729 then
				--ignora i conosciuti a meno di specifiche differenti
				--itemID ~= 207729 forzatura per mostrarne sempre e solo 1 Fyr'alath
				local name, link = FuocoGetItemInfo(itemID)
				if link then
					local iconPath = FuocoGetItemIcon(itemID)
					local icon1 = ""
					if iconPath then
						icon1 = string.format("|T%s:16:16|t", tostring(iconPath))
					end
					local tag = posseduto and " " .. COLverde1 .. "[✓]|r" or ""
					table.insert(parts, icon1 .. link .. tag)
				else
					-- fallback se non è ancora in cache
					if not not_show_item_loading then table.insert(parts, ("loading item:%d"):format(itemID)) end
				end
			end
		end
	end

	if #parts == 0 then
		return "", true
	end

	return table.concat(parts, "\n"), false
end
local function FuocoNoteGetDiffLabel(diffID)
	--https://wowpedia.fandom.com/wiki/DifficultyID
	if diffID == 16 then
		return "M"
	elseif diffID == 15 then
		return "H"
	elseif diffID == 14 then
		return "N"
	elseif diffID == 23 then
		return "M0+" --"MM+"
	elseif diffID == 1 then
		return "NM"
	elseif diffID == 2 then
		return "HC"
	elseif diffID == 3 then
		return "10N"
	elseif diffID == 4 then
		return "25N"
	elseif diffID == 5 then
		return "10HC"
	elseif diffID == 6 then
		return "25HC"
	elseif diffID == 7 or diffID == 17 then -- 17 prima di SoO
		return "LFR"
	elseif diffID == 233 then
		return "Mflex"
	elseif diffID == 0 then
		return L.Tutte1
	else
		return tostring(diffID or "?")
	end
end

local function MostraOggetti()
	local righe = {}

	-- se vuoi includere ANCHE gli ID extra messi in lootSet dai dropIDs,
	-- puoi iterare lootSet invece di tabellaLoot
	for _, itemID in ipairs(tabellaLoot) do
		if type(itemID) == "number" then
			local posseduto = fuoconoteIsCollectibleOwned(itemID)

			-- se db.MostraQuestFatte == false, salta quelli già ottenuti
			if db.MostraQuestFatte or not posseduto then
				local name, link = FuocoGetItemInfo(itemID)
				if link then
					local iconPath = FuocoGetItemIcon(itemID)
					local icon1 = iconPath and string.format("|T%s:16:16|t", tostring(iconPath)) or ""
					local tag = posseduto and " " .. COLverde1 .. "[✓]|r" or ""
					table.insert(righe, icon1 .. link .. tag)
				else
					if not not_show_item_loading then table.insert(righe, ("loading item:%d"):format(itemID)) end
				end
			end
		end
	end

	if #righe == 0 then
		--return "Nessun oggetto da mostrare"
		return ""
	end

	-- uno per riga
	return table.concat(righe, "\n")
end


----------------------------------------------------
-- Helpers condivisi per i link fuoconoteway
----------------------------------------------------

-- Splitta un link fuoconoteway sui ":" e ritorna i campi.
-- Funziona sia col linkData completo  ("fuoconoteway:2405:38 68;37 60:1:12345")
-- sia col payload del gmatch interno  (":2405:38 68;37 60:1:12345")
local function FuocoWayParseLink(str)
	local parts = {}
	for s in (str .. ":"):gmatch("([^:]*):") do
		parts[#parts + 1] = s
	end
	local si = 1
	while si <= #parts and not tonumber(parts[si]) do
		si = si + 1
	end
	if si > #parts then
		return nil, nil, nil, nil
	end
	local mapID     = tonumber(parts[si])
	local coords    = parts[si + 1] or ""
	local tipo      = tonumber(parts[si + 2]) -- nil se assente
	local idPassato = parts[si + 3] or nil    -- stringa "12345" o "12345,12346" o nil

	return mapID, coords, tipo, idPassato
end
-- Risolve il titolo del waypoint dai parametri opzionali.
--   tipo=1  idPassato è un itemID  → FuocoGetItemInfo
--   tipo=2  idPassato è un npcID   → Fuoco.Lib.GetBossName
local function FuocoWayGetTitle(tipo, idPassato)
	if tipo and idPassato then
		local nomi = {}
		for idStr in (idPassato .. ","):gmatch("([^,]+),") do
			local id = tonumber(idStr)
			if id then
				local nome
				if tipo == 1 then
					nome = FuocoGetItemInfo(id)
				elseif tipo == 2 then
					nome = Fuoco.Lib.GetBossName(id)
				end
				if nome and nome ~= "" then
					nomi[#nomi + 1] = nome
				end
			end
		end
		if #nomi > 0 then
			return "FuocoNote: " .. table.concat(nomi, ", ")
		end
	end
	return "FuocoNote"
end

-- Aggiunge un singolo waypoint (TomTom o pin nativo CMap).
local function FuocoWayAddPoint(mapID, wx, wy, title)
	if TomTom and TomTom.AddWaypoint then
		TomTom:AddWaypoint(mapID, wx, wy, {
			title      = title,
			persistent = false,
			minimap    = true,
			world      = true,
		})
	elseif CMap and CMap.CanSetUserWaypointOnMap
		and CMap.CanSetUserWaypointOnMap(mapID)
		and UiMapPoint and UiMapPoint.CreateFromCoordinates then
		CMap.SetUserWaypoint(UiMapPoint.CreateFromCoordinates(mapID, wx, wy))
		if CSuperTrack and CSuperTrack.SetSuperTrackedUserWaypoint then
			CSuperTrack.SetSuperTrackedUserWaypoint(true)
		end
	end
end

-- handler condiviso per tutti i SimpleHTML (celle boss, quest e text1)
local function HandleHyperlinkClick(self, linkData, linkText, button)
	local linkType, payload = linkData:match("(.-):(.*)")

	if linkType == "fuocolink" then
		local linkIndex = tonumber(payload:match("(%d+)"))
		local url = linkIndex and FuocoLinkURLs[linkIndex]
		if not url then return end

		if not FuocoLinkPopup then
			FuocoLinkPopup = CreateFrame("Frame", "FuocoLinkPopupFrame", UIParent, "BasicFrameTemplateWithInset")
			FuocoLinkPopup:SetSize(460, 110)
			FuocoLinkPopup:SetPoint("CENTER")
			FuocoLinkPopup:SetMovable(true)
			FuocoLinkPopup:EnableMouse(true)
			FuocoLinkPopup:RegisterForDrag("LeftButton")
			FuocoLinkPopup:SetScript("OnDragStart", FuocoLinkPopup.StartMoving)
			FuocoLinkPopup:SetScript("OnDragStop",  FuocoLinkPopup.StopMovingOrSizing)
			FuocoLinkPopup.TitleBg:SetHeight(24)
			FuocoLinkPopup:SetFrameStrata("DIALOG")  -- ← sopra UI normale, sotto tooltip
			FuocoLinkPopup:SetFrameLevel(20)
			FuocoLinkPopup:SetToplevel(true)

			local titleText = FuocoLinkPopup:CreateFontString(nil, "OVERLAY", "GameFontNormal")
			titleText:SetPoint("TOP", FuocoLinkPopup, "TOP", 0, -6)
			titleText:SetText(L.apriLink)

			local eb = CreateFrame("EditBox", nil, FuocoLinkPopup, "InputBoxTemplate")
			eb:SetSize(400, 26)
			eb:SetPoint("CENTER", 0, -8)
			eb:SetAutoFocus(false)
			eb:SetMaxLetters(512)
			eb:SetScript("OnEscapePressed", function() FuocoLinkPopup:Hide() end)
			FuocoLinkPopup.editBox = eb
		end

		FuocoLinkPopup.editBox:SetText(url)
		FuocoLinkPopup.editBox:SetFocus()
		FuocoLinkPopup.editBox:HighlightText()
		FuocoLinkPopup:Raise()  -- ← porta in cima dentro la strata
		FuocoLinkPopup:Show()
		return
	end

	if linkType == "fuoconoteway" then
		local mapID, coords, tipo, idPassato = FuocoWayParseLink(linkData)
		if not mapID then return end

		local title = FuocoWayGetTitle(tipo, idPassato)
		local x, y
		for x1, y1 in (coords or ""):gmatch("(%d+%.?%d*)%s+(%d+%.?%d*)") do
			x, y = tonumber(x1), tonumber(y1)
			if x and y then
				FuocoWayAddPoint(mapID, x / 100, y / 100, title)
			end
		end
		if TomTom and TomTom.SetClosestWaypoint then
			TomTom:SetClosestWaypoint()
		end
		return
	end

	-- tasto destro su un link achievement → apre il pannello Achievement
	if linkType == "achievement" and button == "RightButton" then
		local achiID = tonumber(payload:match("^(%d+)"))
		if achiID then
			if not AchievementFrame then
				C_AddOns.LoadAddOn("Blizzard_AchievementUI")
			end
			if AchievementFrame then
				ShowUIPanel(AchievementFrame)
				if AchievementFrame_SelectAchievement then
					AchievementFrame_SelectAchievement(achiID)
				end
			end
		end
		return -- non passare a SetItemRef
	end


	if linkType == "fuoconoteexp" then
		if UpdateText_updating then return end
		local exp = payload
		if not ExpansionCollapsed then
			ExpansionCollapsed = db.ExpansionCollapsed or {}
			db.ExpansionCollapsed = ExpansionCollapsed
		end
		ExpansionCollapsed[exp] = not ExpansionCollapsed[exp]
		UpdateText()
		return
	end
	SetItemRef(linkData, linkText, button, self)
end


local function MakeQuestCell(parent)
	local sh = CreateFrame("SimpleHTML", nil, parent, "InlineHyperlinkFrameTemplate")
	sh:EnableMouse(true)
	sh:SetFontObject("p", FuocoNoteFont)
	sh:SetScript("OnHyperlinkEnter", function(s, linkData)
		GameTooltip:SetOwner(s, "ANCHOR_CURSOR")
		GameTooltip:SetHyperlink(linkData)
		GameTooltip:Show()
	end)
	sh:SetScript("OnHyperlinkLeave", function() GameTooltip:Hide() end)
	sh:SetScript("OnHyperlinkClick", HandleHyperlinkClick) -- ← usa l'handler condiviso
	return sh
end


local function WrapCellHTML(text)
	text = tostring(text or ""):gsub("\n", "<br/>")
	return "<html><body><p align='left'>" .. text .. "</p></body></html>"
end

local function BossRow_Get(i, cols)
	if not bossRowPool[i] then
		local rf = CreateFrame("Frame", nil, bossFrame)
		rf:SetPoint("TOPLEFT", bossFrame, "TOPLEFT", 0, 0)
		rf:SetSize(StartW, ROW_H_MIN)
		local cells = {}
		for c, col in ipairs(cols) do
			local sh = MakeQuestCell(rf)
			sh:SetPoint("TOPLEFT", rf, "TOPLEFT", col.x, 0)
			sh:SetWidth(col.w)
			sh:SetHeight(ROW_H_MIN)
			cells[c] = sh
		end
		local bg = rf:CreateTexture(nil, "BACKGROUND", nil, -1)
		bg:SetAllPoints(rf)
		bg:SetColorTexture(0, 0, 0, 0)
		local sep = rf:CreateTexture(nil, "BACKGROUND")
		sep:SetColorTexture(0.4, 0.4, 0.4, 0.5)
		sep:SetHeight(1)
		sep:SetPoint("BOTTOMLEFT", rf, "BOTTOMLEFT", 0, 0)
		sep:SetPoint("BOTTOMRIGHT", rf, "BOTTOMRIGHT", 0, 0)
		bossRowPool[i] = { frame = rf, cells = cells, bg = bg }
	else
		local row = bossRowPool[i]
		for c, col in ipairs(cols) do
			if row.cells[c] then
				row.cells[c]:SetPoint("TOPLEFT", row.frame, "TOPLEFT", col.x, 0)
				row.cells[c]:SetWidth(col.w)
			end
		end
	end
	return bossRowPool[i]
end

-- ============================================================
-- GetRenownInfo  (tipo=9) - Midnight Major Factions
-- ============================================================
-- Tabella nomi reaction classici (usata come fallback)
local REACTION_NAMES = {
	[1] = "Ostile",
	[2] = "Nemico",
	[3] = "Diffidente",
	[4] = "Neutrale",
	[5] = "Amichevole",
	[6] = "Onorevole",
	[7] = "Riverito",
	[8] = "Esaltato",
}

local function IsMajorFaction(factionID)
	if not C_MajorFactions or not C_MajorFactions.GetMajorFactionData then
		return false
	end
	return C_MajorFactions.GetMajorFactionData(factionID) ~= nil
end

local function GetRenownInfo(factionID, renownNeeded, valutaID, quantity, npcID)
	local nomeFazione, curLevel, earned, threshold, hasMax

	-- -------------------------------------------------------
	-- CASO 1: Major Faction (es. Corte di Lunargenta 2710)
	-- -------------------------------------------------------
	if IsMajorFaction(factionID) then
		local data  = C_MajorFactions.GetMajorFactionData(factionID)
		if not data then
			return COLgrigio1 .. L.renownFazioneND1:format(factionID) .. "|r"
		end
		nomeFazione = EscapeHTML(data.name or ("Fazione " .. factionID))
		curLevel    = data.renownLevel or 0
		earned      = data.renownReputationEarned or 0
		threshold   = data.renownLevelThreshold or 0
		hasMax      = C_MajorFactions.HasMaximumRenown
			and C_MajorFactions.HasMaximumRenown(factionID)

		-- -------------------------------------------------------
		-- CASO 2: Friendship Faction (es. Magistri 2711, Cavalieri 2712, ecc.)
		-- -------------------------------------------------------
	elseif C_GossipInfo and C_GossipInfo.GetFriendshipReputation then
		local fd = C_GossipInfo.GetFriendshipReputation(factionID)

		if fd and fd.friendshipFactionID then
			nomeFazione    = EscapeHTML(fd.name or ("Fazione " .. factionID))
			local stepSize = 500
			curLevel       = math.floor(fd.standing / stepSize) + 1
			local isAtCap  = (fd.nextThreshold == nil)
			hasMax         = isAtCap or (renownNeeded and curLevel >= renownNeeded)

			if isAtCap then
				earned    = fd.standing - (fd.reactionThreshold or 0)
				threshold = (fd.maxRep or 0) - (fd.reactionThreshold or 0)
			else
				earned    = fd.standing % stepSize
				threshold = stepSize
			end
		else
			-- fd esiste ma non è friendship → trattala come classica
			local info = C_Reputation.GetFactionDataByID(factionID)
			if not info then
				return COLgrigio1 .. L.renownFazioneND1:format(factionID) .. "|r"
			end
			nomeFazione = EscapeHTML(info.name or ("Fazione " .. factionID))
			curLevel    = info.reaction or 0
			earned      = info.currentStanding or 0
			threshold   = info.nextReactionThreshold or 0
			hasMax      = (renownNeeded and curLevel >= renownNeeded) or (curLevel >= 8)
		end

		-- -------------------------------------------------------
		-- CASO 3: Reputazione classica (fallback — C_GossipInfo non disponibile)
		-- -------------------------------------------------------
	else
		local info = C_Reputation.GetFactionDataByID(factionID)
		if not info then
			return COLgrigio1 .. L.renownFazioneND1:format(factionID) .. "|r"
		end
		nomeFazione = EscapeHTML(info.name or ("Fazione " .. factionID))
		curLevel    = info.reaction or 0
		earned      = info.currentStanding or 0
		threshold   = info.nextReactionThreshold or 0
		hasMax      = (renownNeeded and curLevel >= renownNeeded) or (curLevel >= 8)
	end

	-- -------------------------------------------------------
	-- Costruzione stringa output
	-- -------------------------------------------------------
	local reached    = hasMax or (renownNeeded and curLevel >= renownNeeded)
	local factionCol = reached and COLverde1 or COLgiallo1
	local levelCol   = reached and COLverde2 or COLrosso1
	local levelLabel = renownNeeded
		and string.format(" %d/%d", curLevel, renownNeeded)
		or (" " .. curLevel)

	local npcName    = ''
	if npcID and npcID ~= 0 then
		npcName = (Fuoco.Lib.GetBossName(npcID) or ("npc:" .. npcID)) .. " - "
	end

	local str = factionCol .. npcName .. " " .. nomeFazione .. "|r"
		.. levelCol .. levelLabel .. "|r"

	-- Progresso XP verso il prossimo livello
	if not hasMax and threshold > 0 then
		str = str .. " " .. COLgrigio1
			.. string.format("(%d/%d)", earned, threshold) .. "|r\n"
	end

	-- Checkmark se raggiunto
	if reached then
		str = str .. " " .. COLverde1 .. L.renownRaggiunto1 .. "|r"
	end

	-- -------------------------------------------------------
	-- Costo in valuta
	-- -------------------------------------------------------
	if valutaID and valutaID ~= 0 then
		local datiCurrency = C_CurrencyInfo and C_CurrencyInfo.GetCurrencyInfo(valutaID)
		if datiCurrency then
			local iconCurrency = datiCurrency.iconFileID
				and string.format("|T%s:16:16|t", tostring(datiCurrency.iconFileID))
				or ""
			local Currencylink = iconCurrency
				.. "|cff1eff00|Hcurrency:" .. valutaID .. ":0|h["
				.. datiCurrency.name .. "]|h|r"
			local qtyStr = quantity and (COLgiallo1 .. tostring(quantity) .. "|r" .. " ") or ""
			str = str .. "  " .. qtyStr .. Currencylink
		end
	end

	return str
end

local function GetParagonInfo(factionID)
	local factionData = C_Reputation.GetFactionDataByID(factionID)
	if not factionData then
		return COLgrigio1 .. L.paragonFazione1:format(factionID) .. "|r"
	end

	local NomeFazione = EscapeHTML(factionData.name or L.paragonFazione1:format(factionID))

	-- Controlla il livello reputazione (8 = Esaltato)
	-- _G["FACTION_STANDING_LABEL"..n] restituisce il nome localizzato del livello
	local standing = factionData.reaction or 0

	if standing < 8 then
		local standingName = _G["FACTION_STANDING_LABEL" .. standing] or ("?" .. standing)

		local currentRep   = factionData.currentStanding or 0
		local maxRep       = factionData.nextReactionThreshold or 0
		local minRep       = factionData.currentReactionThreshold or 0

		-- toNext calcolato sul range del livello corrente
		local toNext       = maxRep - currentRep
		if toNext < 0 then toNext = 0 end

		return COLceleste1 .. NomeFazione .. "|r"
			.. "  |cffaaaaaa[" .. standingName .. "]|r"
			.. "  " .. COLgiallo1
			.. L.paragonVersoEsaltato1:format(toNext)
			.. "|r"
	end


	-- Esaltato: verifica se la fazione supporta il Paragon
	if not C_Reputation.IsFactionParagon or not C_Reputation.IsFactionParagon(factionID) then
		return COLgrigio1 .. L.paragonNoParagon1:format(NomeFazione) .. "|r"
	end

	-- Paragon attivo: calcola quanti punti mancano alla prossima cassetta
	local currentValue, threshold, _, hasRewardPending = C_Reputation.GetFactionParagonInfo(factionID)
	if not currentValue or not threshold then
		return COLgrigio1 .. L.paragonNoData1:format(NomeFazione) .. "|r"
	end

	local progress = currentValue % threshold
	local missing  = threshold - progress

	local str      = COLceleste1 .. NomeFazione .. "|r"
		.. "  " .. COLgiallo1 .. L.paragonMancano1:format(missing) .. "|r"

	if hasRewardPending then
		str = str .. "  " .. COLverde1 .. L.paragonPronta1 .. "|r"
	end

	return str
end



local function QuestRow_Get(i, cols)
	if not questRowPool[i] then
		local rf = CreateFrame("Frame", nil, questFrame)
		rf:SetPoint("TOPLEFT", questFrame, "TOPLEFT", 0, 0)
		rf:SetSize(StartW, ROW_H_MIN)
		local cells = {}
		for c, col in ipairs(cols) do
			local sh = MakeQuestCell(rf)
			sh:SetPoint("TOPLEFT", rf, "TOPLEFT", col.x, 0)
			sh:SetWidth(col.w)
			sh:SetHeight(ROW_H_MIN)
			cells[c] = sh
		end
		local bg = rf:CreateTexture(nil, "BACKGROUND", nil, -1)
		bg:SetAllPoints(rf)
		bg:SetColorTexture(0, 0, 0, 0)
		local sep = rf:CreateTexture(nil, "BACKGROUND")
		sep:SetColorTexture(0.4, 0.4, 0.4, 0.5)
		sep:SetHeight(1)
		sep:SetPoint("BOTTOMLEFT", rf, "BOTTOMLEFT", 0, 0)
		sep:SetPoint("BOTTOMRIGHT", rf, "BOTTOMRIGHT", 0, 0)
		questRowPool[i] = { frame = rf, cells = cells, bg = bg }
	else
		-- aggiorna posizioni e larghezze se la finestra è cambiata
		local row = questRowPool[i]
		for c, col in ipairs(cols) do
			if row.cells[c] then
				row.cells[c]:SetPoint("TOPLEFT", row.frame, "TOPLEFT", col.x, 0)
				row.cells[c]:SetWidth(col.w)
			end
		end
	end
	return questRowPool[i]
end


local function MostraBossDaFare(onDone)
	local totalW = math.max((db and db.width or StartW) - 35, BOSS_MIN_W)
	local cols   = GetBossCols(totalW)
	if bossFrame then bossFrame:SetWidth(totalW) end

	local rowsData = {}
	-- intestazione
	table.insert(rowsData, {
		COLgrigio1 .. "#|r",
		COLgiallo1 .. L["boss"] .. "|r",
		COLgiallo1 .. L["Zona1"] .. "|r",
		COLgiallo1 .. L["drop1"] .. "|r",
		COLgiallo1 .. L["diff1"] .. "|r",
	})

	-- raggruppa per espansione (rispetta ExpansionCollapsed)
	local groups, order = {}, {}
	local bossIdx = 0

	local function AddRow(exp, data)
		if not groups[exp] then
			groups[exp] = {}; table.insert(order, exp)
		end
		table.insert(groups[exp], data)
	end

	for _, item1 in ipairs(droplist) do
		local ejID                       = item1[1]
		local bossPos                    = item1[2]
		local diffData                   = item1[3]
		local dropIDs                    = item1[4]
		local achiID                     = item1.achiID or 0

		local diffList                   = (type(diffData) == "table") and diffData or { diffData }

		local bossName                   = "?" .. ejID .. "?"
		local instanceName               = "?" .. ejID .. "?"
		local ejInstanceName, ejBossName = FuocoNoteGetInstanceAndBossNameFromEJ(ejID, bossPos)
		local NascondiIstanza			 = true	-- istanza non trovara (forse ancoda deve uscire)

		if ejInstanceName then
			instanceName = ejInstanceName
			NascondiIstanza = false
		end
		if ejBossName then bossName = ejBossName end

		local espansione = (EJExpByID and EJExpByID[ejID]) or "?"

		local anyNotKilled, anyKilled = false, false
		local diffStates = {}

		for _, diffID in ipairs(diffList) do
			local info   = FindSavedInstanceByEJ(ejID, diffID)
			local killed = false
			if info and info.numEncounters and info.numEncounters > 0
				and bossPos >= 1 and bossPos <= info.numEncounters then
				local nameSaved, _, isKilled = GetSavedInstanceEncounterInfo(info.index, bossPos)
				if nameSaved then bossName = nameSaved end
				killed = isKilled and true or false
			end
			if killed then anyKilled = true else anyNotKilled = true end
			local diffColor = killed and COLrosso1 or COLverde1
			table.insert(diffStates, diffColor .. FuocoNoteGetDiffLabel(diffID) .. "|r")
		end

		if (anyNotKilled or db.MostraBossOggettiFatti) and not NascondiIstanza then
			local dropText, ignoraLinea = FuocoNoteGetDropLinks(dropIDs)
			--
			--		Warglaive of Azzinoth usano achiid -->> forse anche altro
			--
			if type(achiID) == "number" and achiID > 0 then
				ignoraLinea = fuoconoteIsAchievementCompleted(achiID)
			end
			if type(achiID) == "table" then
				ignoraLinea = true
				for _, aid in ipairs(achiID) do
					ignoraLinea = ignoraLinea and fuoconoteIsAchievementCompleted(achiID)
					dropText = dropText .. "\n" .. (fuoconoteGetAchievementLink(aid) or tostring(aid))
				end
			else
				if achiID > 0 then
					dropText = dropText .. "\n" .. (fuoconoteGetAchievementLink(achiID) or tostring(achiID))
				end
			end

			if ignoraLinea and not db.BossDiCuiHoTuttoShow then
				-- skip
			else
				local bossColor = anyNotKilled and COLceleste1 or COLrosso1
				bossIdx = bossIdx + 1
				local bossNumColor = anyNotKilled and COLverde1 or COLrosso1
				local bossNkill = ""
				if item1.conteggioKill then
					bossNkill = " " .. L.tentativi1 .. ": " .. item1.conteggioKill
					if item1.statName and item1.statName ~= "" then
						bossNkill = bossNkill .. " - " .. item1.statName
					end
				end
				AddRow(espansione, {
					bossNumColor .. bossIdx .. "|r", -- colonna #
					bossColor .. bossName .. "|r" .. bossNkill,
					COLgrigio1 .. instanceName .. "|r",
					dropText or "",
					table.concat(diffStates, " "),
				})
			end
		end
	end


	-- intestazione espansioni + righe
	local flatRows = {}
	-- header colonne sempre primo
	rowsData[1].isHeader = true
	table.insert(flatRows, rowsData[1])

	for _, exp in ipairs(order) do
		local collapsed = ExpansionCollapsed and ExpansionCollapsed[exp]
		local simbolo   = collapsed and "+" or "-"
		local link      = string.format("|Hfuoconoteexp:%s|h[%s %s]|h", exp, simbolo, exp)
		-- riga espansione (header gruppo) su colonna 1, resto vuoto
		local grow = { "", COLverde2 .. link .. "|r", "", "", "" }
		grow.isGroup = true
		table.insert(flatRows, grow)
		if not collapsed then
			for _, row in ipairs(groups[exp]) do
				table.insert(flatRows, row)
			end
		end
	end

	if #order == 0 then
		table.insert(flatRows, { "", COLgrigio1 .. (L["NoBoss1"] or "Nessun boss") .. "|r", "", "", "" })
	end

	-- firma anti-flicker: se il contenuto è identico all'ultimo render, non ricostruire nulla
	local sigParts = { tostring(totalW) }
	for _, data in ipairs(flatRows) do
		for c = 1, 5 do sigParts[#sigParts + 1] = tostring(data[c] or "") end
	end
	local sig = table.concat(sigParts, "\30")
	if sig == lastBossSig and lastBossH and bossRowPool[1] and bossRowPool[1].frame:IsShown() then
		if onDone then onDone(lastBossH, lastBossCount or bossIdx) end
		return
	end

	-- nascondi le righe residue e popola
	for _, row in ipairs(bossRowPool) do row.frame:Hide() end
	for i, data in ipairs(flatRows) do
		local row = BossRow_Get(i, cols)
		row.frame:SetWidth(totalW)
		if row.bg then
			if data.isHeader then
				row.bg:SetColorTexture(0.25, 0.25, 0.35, 0.6)
			elseif data.isGroup then
				row.bg:SetColorTexture(0.12, 0.35, 0.12, 0.4)
			elseif i % 2 == 0 then
				row.bg:SetColorTexture(1, 1, 1, ROW_BG_ALPHA)
			else
				row.bg:SetColorTexture(0, 0, 0, 0)
			end
		end
		for c = 1, 5 do
			row.cells[c]:SetHeight(MEASURE_ROW_H)
			row.cells[c]:SetText(WrapCellHTML(data[c] or ""))
		end
		row.frame:SetHeight(MEASURE_ROW_H)
		row.frame:Show()
	end

	-- misura e riposiziona
	C_Timer.After(MEASURE_DELAY, function()
		local totalH = 0
		for i = 1, #flatRows do
			local row = bossRowPool[i]
			if not row then break end
			local rowH = ROW_H_MIN
			for c = 1, 5 do
				local ch = row.cells[c]:GetContentHeight() or 0
				if ch > rowH then rowH = ch end
			end
			rowH = rowH + 2
			row.frame:ClearAllPoints()
			row.frame:SetPoint("TOPLEFT", bossFrame, "TOPLEFT", 0, -totalH)
			row.frame:SetHeight(rowH)
			for c = 1, 5 do row.cells[c]:SetHeight(rowH) end
			totalH = totalH + rowH
		end
		bossFrame:SetHeight(totalH + 4)
		lastBossSig   = sig
		lastBossH     = totalH + 4
		lastBossCount = bossIdx
		if onDone then onDone(totalH + 4, bossIdx) end
	end)
end


------------------------------------
local function BuildZonaStr(idzona, currentMapID)
	if not idzona then
		return ""
	end

	-- caso speciale 0
	if type(idzona) ~= "table" and idzona == 0 then
		return "Not ready" --"mapID:??"
	end

	-- helper per un singolo mapID
	local function oneZone(mapID)
		if not mapID or mapID == 0 then
			return nil
		end
		local info = C_Map.GetMapInfo(mapID)
		local name = info and info.name or ("mapID:" .. mapID)
		local col  = (currentMapID == mapID) and COLgiallo1 or COLgrigio1
		return col .. name .. "|r"
	end

	if type(idzona) ~= "table" then
		local s = oneZone(idzona)
		return s or ""
	end

	local parts = {}
	for _, mapID in ipairs(idzona) do
		local s = oneZone(mapID)
		if s then
			table.insert(parts, s)
		end
	end

	return table.concat(parts, "\n")
end


local function MostraQuestDaFare(onDone, startIdx)
	local totalW = math.max((db and db.width or StartW) - 35, QuestMinW)
	local cols   = GetQuestCols(totalW)
	if questFrame then questFrame:SetWidth(totalW) end

	local rowsData = {}
	local currentMapID = C_Map.GetBestMapForUnit and C_Map.GetBestMapForUnit("player") or nil

	-- intestazione
	local headerRow = {
		COLgrigio1 .. "#|r",
		COLgiallo1 .. L.Zona1 .. "|r",
		COLgiallo1 .. L.Obiettivo1 .. "|r",
		COLgiallo1 .. L.drop1 .. "|r",
	}
	headerRow.isHeader = true
	table.insert(rowsData, headerRow)

	local questIdx = startIdx or 0
	for _, quest in ipairs(IDQuest) do
		local id                = quest.id or 0
		local achiID            = quest.achiID or 0
		local tipo              = quest.tipo
		local note              = quest.note or ""
		local idzona            = quest.idzona
		local drop              = quest.drop
		local npcID             = quest.npc
		local valutaID          = quest.valutaID
		local quantity          = quest.quantity
		local OggettoDiScambio  = quest.OggettoDiScambio
		local questPreRequisito = quest.questPreRequisito
		local factionID         = quest.factionID
		local VersioneGioco     = quest.VersioneGioco
		local EventAttivoID     = quest.EventAttivoID


		if VersioneGioco and VersioneGioco ~= "" and VersioneGioco > WowVersion then
			--if false then
			--print(VersioneGioco.." "..WowVersion.." "..id..":"..tipo)
		else
			if EventAttivoID then
				if FuocoGetActiveEvent(EventAttivoID) then
					note = COLrosso1 .. "&gt;&gt;&gt;&gt;&gt;|r" ..COLverde1 .. L.TWattiva .. "|r"..COLrosso1.."&lt;&lt;&lt;&lt;&lt;|r\n" .. note
				end
			end
			if VersioneGioco and VersioneGioco ~= "" and VersioneGioco == WowVersion then
				note = COLverde1 .. L.aggiunti_con_questa_versione .. "|r\n" .. note
			end
			if quantity then quantity = tostring(quantity) end

			local completata = false

			if id > 0 then
				completata = C_QuestLog.IsQuestFlaggedCompleted(id)
			end

			if tipo == 4 and npcID then
				local npcList = type(npcID) == "table" and npcID or { npcID }
				completata = true
				for _, entry in ipairs(npcList) do
					if not entry then break end
					local sqid = type(entry) == "table" and (entry.id2Quest or 0) or (tonumber(entry) or 0)
					if sqid == 0 or not C_QuestLog.IsQuestFlaggedCompleted(sqid) then
						completata = false
						break
					end
				end
			end

			if type(achiID) == "number" and achiID > 0 then
				completata = completata and fuoconoteIsAchievementCompleted(achiID)
			end
			if type(achiID) == "table" then
				completata = true
				for _, aid in ipairs(achiID) do
					completata = completata and fuoconoteIsAchievementCompleted(achiID)
				end
			end

			--				-- tipo=9: completata quando curLevel >= renownNeeded
			--				if tipo == 9 and factionID and factionID ~= 0 then
			--				    if C_MajorFactions and C_MajorFactions.GetMajorFactionData then
			--				        local mfData = C_MajorFactions.GetMajorFactionData(factionID)
			--				        if mfData then
			--				            local needed = quest.renownNeeded or 0
			--				            completata = needed > 0 and (mfData.renownLevel or 0) >= needed
			--				        end
			--				    end
			--				end

			if (not completata) or (db.MostraQuestFatte and (tipo == 1 or tipo == 4)) or db.MostraDropKnown then
				-- colore globale riga: rosso=fatto, verde=da fare
				local rowColor = completata and COLrosso1 or COLverde1

				-- ZONA
				local zonaStr = BuildZonaStr(idzona, currentMapID)

				-- NOTA per tipo
				local notaStr = note

				if tipo == 1 then
					if OggettoDiScambio then
						local _, link = FuocoGetItemInfo(OggettoDiScambio)
						if link then
							notaStr = notaStr .. link .. "\n"
						end
					end
					if npcID then
						-- colore in base allo stato completamento
						notaStr = notaStr .. rowColor .. (Fuoco.Lib.GetBossName(npcID) or ("npc:" .. npcID)) .. "|r\n"
					end
				elseif tipo == 2 then
					if npcID then
						-- colore in base allo stato completamento
						notaStr = notaStr .. rowColor .. (Fuoco.Lib.GetBossName(npcID) or ("npc:" .. npcID)) .. "|r"
					end
				elseif tipo == 4 then
					if npcID then
						local parts = {}
						local npcList = type(npcID) == "table" and npcID or { npcID }
						for _, entry in ipairs(npcList) do
							local sid  = type(entry) == "table" and (entry.idnpc or entry[1]) or entry
							local sqid = type(entry) == "table" and (entry.id2Quest or 0) or 0
							if sid then
								local bName = Fuoco.Lib.GetBossName(sid) or ("npc:" .. tostring(sid))
								if sqid > 0 then
									local done = C_QuestLog.IsQuestFlaggedCompleted(sqid)
									bName = (done and COLrosso1 or COLverde1) .. bName .. "|r"
								else
									bName = COLgrigio1 .. bName .. "|r"
								end
								table.insert(parts, bName)
							end
						end
						notaStr = table.concat(parts, "\n")
					end
				elseif tipo == 5 or tipo == 6 then
					local parts = {}
					if type(achiID) == "table" then
						for _, aid in ipairs(achiID) do
							table.insert(parts, fuoconoteGetAchievementLink(aid) or tostring(aid))
						end
					else
						if achiID and achiID > 0 then
							table.insert(parts, fuoconoteGetAchievementLink(achiID) or tostring(achiID))
						end
					end
					notaStr = notaStr .. table.concat(parts, ", ")

					--		          elseif tipo == 6 then
					local parts = {}
					if quantity then
						notaStr = notaStr .. quantity .. " "
					end
					if valutaID and valutaID > 0 then
						local datiCurrency = C_CurrencyInfo.GetCurrencyInfo(valutaID)
						local iconCurrency = datiCurrency.iconFileID and
							string.format("|T%s:16:16|t", tostring(datiCurrency.iconFileID)) or ""
						local Currencylink = iconCurrency ..
							"|cff1eff00|Hcurrency:" .. valutaID .. ":0|h[" .. datiCurrency.name .. "]|h|r"

						if type(npcID) == "table" then
							for _, localNPCid in ipairs(npcID) do
								table.insert(parts, (Fuoco.Lib.GetBossName(localNPCid) or ("npc:" .. npcID)))
							end
						else
							table.insert(parts, (Fuoco.Lib.GetBossName(npcID) or ("npc:" .. npcID)))
						end
						notaStr = notaStr .. Currencylink .. " -> " .. table.concat(parts, "\n")
					end
				elseif tipo == 7 then
					if id and id > 0 then
						local link = "|cffffd100|Hquest:" ..
							id .. ":0|h[" .. (C_QuestLog.GetTitleForQuestID(id) or "----") .. "]|h|r\n"
						notaStr = link .. " " .. notaStr
					end
					if npcID then
						-- colore in base allo stato completamento
						notaStr = notaStr .. rowColor .. (Fuoco.Lib.GetBossName(npcID) or ("npc:" .. npcID)) .. "|r\n"
					end
				elseif tipo == 8 then
					if factionID and factionID ~= 0 then
						notaStr = notaStr .. "Paragon reputation: " .. GetParagonInfo(factionID)
					end
				elseif tipo == 9 then
					if factionID and factionID ~= 0 then
						notaStr = notaStr .. GetRenownInfo(factionID, quest.renownNeeded,
							quest.valutaID, quest.quantity, npcID)
					end
				else
					-- tipo 1, 3 e altri: colora la nota col colore riga
					if notaStr ~= "" then
						notaStr = rowColor .. notaStr .. "|r"
					end
				end

				-- DROP
				local posseduto = true
				local dropParts = {}
				if drop and #drop > 0 then
					for _, itemID in ipairs(drop) do
						if type(itemID) == "number" then
							local poss = fuoconoteIsCollectibleOwned(itemID)
							posseduto  = posseduto and poss
							if not poss then
								missingDropCount = missingDropCount + 1
							end
							if (db.MostraDropKnown or not poss) and not fuoconoteIsHiddenByFilter(itemID) and not fuoconoteIsHiddenByFilter(itemID) then
								local _, link = FuocoGetItemInfo(itemID)
								if link then
									local iconPath = FuocoGetItemIcon(itemID)
									local icon1 = iconPath and string.format("|T%s:16:16|t", tostring(iconPath)) or ""
									local s = icon1 .. link
									if poss then s = s .. " " .. COLverde1 .. "[✓]|r" end
									table.insert(dropParts, s)
								else
									if not not_show_item_loading then table.insert(dropParts, ("loading item:%d"):format(itemID)) end
								end
							end
						end
					end
				end

				if tipo == 3 and OggettoDiScambio then
					if quantity then
						notaStr = notaStr .. quantity .. " "
					end
					local _, link = FuocoGetItemInfo(OggettoDiScambio)
					if link then
						local iconPath = FuocoGetItemIcon(OggettoDiScambio)
						local icon1 = iconPath and string.format("|T%s:16:16|t", tostring(iconPath)) or ""
						notaStr = notaStr .. icon1 .. link
					else
						notaStr = notaStr .. ("item:" .. OggettoDiScambio)
					end
				end

				local questTitleList = ""
				if questPreRequisito then
					for _, questID in ipairs(questPreRequisito) do
						if not C_QuestLog.IsQuestFlaggedCompleted(questID) then
							local title = C_QuestLog.GetTitleForQuestID(questID)
							if title then
								local link = "|cffffd100|Hquest:" .. questID .. ":0|h[" .. title .. "]|h|r"
								questTitleList = (questTitleList .. "\n" .. link)
							end
						end
					end
				end
				if questTitleList ~= "" then questTitleList = "\n" .. L.questNeeded1 .. questTitleList end


				local dropStr = table.concat(dropParts, "\n")

				if ((db.MostraQuestFatte and completata) or (db.MostraDropKnown or not posseduto)) and dropStr ~= '' then
					questIdx = questIdx + 1
					table.insert(rowsData, {
						rowColor .. questIdx .. "|r", -- # colorato verde/rosso
						zonaStr,
						notaStr .. questTitleList,
						dropStr,
					})
				end
			end
		end
	end

	if questIdx == 0 then
		table.insert(rowsData, { "", COLgrigio1 .. (L.NoQuest1 or "Nessuna quest") .. "|r", "", "" })
	end

	-- firma anti-flicker: salta la ricostruzione se il contenuto non è cambiato
	local sigParts = { tostring(totalW) }
	for _, data in ipairs(rowsData) do
		for c = 1, 4 do sigParts[#sigParts + 1] = tostring(data[c] or "") end
	end
	local sig = table.concat(sigParts, "\30")
	if sig == lastQuestSig and lastQuestH and questRowPool[1] and questRowPool[1].frame:IsShown() then
		if onDone then onDone(lastQuestH) end
		return
	end

	-- nascondi le righe residue e popola con altezza grande per misurazione
	for _, row in ipairs(questRowPool) do row.frame:Hide() end
	for i, data in ipairs(rowsData) do
		local row = QuestRow_Get(i, cols)
		row.frame:SetWidth(totalW)
		if row.bg then
			if data.isHeader then
				row.bg:SetColorTexture(0.25, 0.25, 0.35, 0.6)
			elseif i % 2 == 0 then
				row.bg:SetColorTexture(1, 1, 1, ROW_BG_ALPHA)
			else
				row.bg:SetColorTexture(0, 0, 0, 0)
			end
		end
		for c = 1, 4 do
			row.cells[c]:SetHeight(MEASURE_ROW_H)
			row.cells[c]:SetText(WrapCellHTML(data[c] or ""))
		end
		row.frame:SetHeight(MEASURE_ROW_H)
		row.frame:Show()
	end

	-- misura altezza reale e riposiziona dopo il rendering
	C_Timer.After(MEASURE_DELAY, function()
		local totalH = 0
		for i = 1, #rowsData do
			local row = questRowPool[i]
			if not row then break end
			local rowH = ROW_H_MIN
			for c = 1, 4 do
				local ch = row.cells[c]:GetContentHeight() or 0
				if ch > rowH then rowH = ch end
			end
			rowH = rowH + 2
			row.frame:ClearAllPoints()
			row.frame:SetPoint("TOPLEFT", questFrame, "TOPLEFT", 0, -totalH)
			row.frame:SetHeight(rowH)
			for c = 1, 4 do row.cells[c]:SetHeight(rowH) end
			totalH = totalH + rowH
		end
		questFrame:SetHeight(totalH + 4)
		lastQuestSig = sig
		lastQuestH   = totalH + 4
		if onDone then onDone(totalH + 4) end
	end)
end

----------------------------------------------------
-- aggiornamento
----------------------------------------------------
UpdateText = function()
	if not forzaUdate1 then
		if not mainFrame:IsShown() then return end
	end
	forzaUdate1 = false
	if UpdateText_updating then return end
	UpdateText_updating = true
	TuttiILinkSonoCaricati = true

	-- salva lo scroll per ripristinarlo dopo la ricostruzione (evita salti di posizione)
	local savedScroll = scrollFrame and scrollFrame:GetVerticalScroll() or 0

	-- testo oggetti liberi (tabellaLoot) — rimane in SimpleHTML
	local oggetti1 = ""
	local oggetti2 = MostraOggetti()
	if oggetti2 and oggetti2 ~= "" then
		oggetti1 = "\n" .. COLverde2 .. L["obj1"] .. "|r\n" .. oggetti2
	end

	missingDropCount = 0

	-- SimpleHTML solo per oggetti liberi + titoli
	text1:SetHeight(MEASURE_TEXT_H)

	C_Timer.After(MEASURE_DELAY, function()
		if not content1 or not bossFrame or not questFrame then
			UpdateText_updating = false; return
		end

		local h1 = math.max(text1:GetContentHeight() or 60, 20)
		text1:SetHeight(h1)

		local BOSS_HDR_H = 24

		bossHeaderFrame:ClearAllPoints()
		bossHeaderFrame:SetPoint("TOPLEFT", content1, "TOPLEFT", 0, -h1)
		bossHeaderFrame:SetWidth(db.width - 35)

		bossFrame:ClearAllPoints()
		bossFrame:SetPoint("TOPLEFT", content1, "TOPLEFT", 0, -(h1 + BOSS_HDR_H))
		bossFrame:SetWidth(db.width - 35)

		MostraBossDaFare(function(h_boss, bossCount) -- ← bossCount aggiunto
			questFrame:ClearAllPoints()
			questFrame:SetPoint("TOPLEFT", content1, "TOPLEFT", 0, -(h1 + BOSS_HDR_H + h_boss))
			questFrame:SetWidth(db.width - 35)

			MostraQuestDaFare(function(h2)
				textBottom:Hide()
				content1:SetHeight(h1 + BOSS_HDR_H + h_boss + h2 + 20)
				-- ripristina la posizione di scroll (clampata alla nuova altezza)
				if scrollFrame then
					local maxScroll = math.max(0, content1:GetHeight() - scrollFrame:GetHeight())
					scrollFrame:SetVerticalScroll(math.min(savedScroll, maxScroll))
				end
				UpdateText_updating = false

				local questTitle = "\n" .. COLverde2 .. L["obj2"] .. "|r"
				titleText:SetText(addonName .. " - " .. (leaderName or "")
					.. " - |cffff9900" .. L.mancanti1 .. " [" .. missingDropCount .. "]|r")
				text1:SetText(ToSimpleHTMLLeft(oggetti1 .. questTitle))
			end, bossCount) -- ← startIdx passato
		end)
	end)
end


----------------------------------------------------
-- init
----------------------------------------------------
local function Initialize()
	local realm                                                         = GetRealmName()
	nome_pg                                                             = UnitName("player")

	local version, build, date, tocversion, localizedVersion, buildType = GetBuildInfo()
	WowVersion                                                          = version

	FuocoNoteDB[realm]                                                  = FuocoNoteDB[realm] or {}
	FuocoNoteDB[realm][nome_pg]                                         = FuocoNoteDB[realm][nome_pg] or {}

	db                                                                  = FuocoNoteDB[realm][nome_pg]

	db.ExpansionCollapsed                                               = db.ExpansionCollapsed or {}
	ExpansionCollapsed                                                  = db
		.ExpansionCollapsed -- alias alla tabella salvata

	db.posX                                                             = db.posX or 500
	db.posY                                                             = db.posY or -300
	db.width                                                            = db.width or StartW
	db.height                                                           = db.height or 400
	db.BossDiCuiHoTuttoShow                                             = db.BossDiCuiHoTuttoShow or false
	db.MostraQuestFatte                                                 = db.MostraQuestFatte or false
	db.MostraBossOggettiFatti                                           = db.MostraBossOggettiFatti or false
	db.MostraDropKnown                                                  = db.MostraDropKnown or false
	db.HideInCombat                                                     = db.HideInCombat or true
	db.minimized                                                        = db.minimized or false
	db.collapsedX                                                       = db.collapsedX or nil
	db.collapsedY                                                       = db.collapsedY or nil
	db.HidePet                                                          = db.HidePet or false
	db.HideMount                                                        = db.HideMount or false
	db.HideToy                                                          = db.HideToy or false
	db.HideIllusion                                                     = db.HideIllusion or false
	db.HideTransmog                                                     = db.HideTransmog or false

	if db.ShowMain == nil then
		db.ShowMain = true
	end
	db.ShowMain = db.ShowMain or false
	if db.SayGZ == nil then
		db.SayGZ = true
	end
	db.SayGZ		= true
	--db.SayGZ		= db.SayGZ or true

	db.FrameAlpha = db.FrameAlpha or 0.6 -- opacità base fuori mouseover

	local function FuocoNoteRaiseMainFrame()
		if not mainFrame then return end
		mainFrame:SetFrameStrata("DIALOG")
		mainFrame:SetFrameLevel(10)
		mainFrame:SetToplevel(true)
		mainFrame:Raise()
	end

	-- ====================================================
	-- Aggiornamento event-driven con debounce (RefreshSec)
	-- ====================================================
	local minRefreshSec = 5 -- secondi ogni refresh dopo i primi maxFastRefresh
	local minRefreshSecFast = 1 -- recondi refresh iniziali
	local maxFastRefresh = 6 -- massimo
	local fastRefreshDone = 0 -- quanti ne ho fatti
	local updatePending = false

	ScheduleUpdate = function()
		if not mainFrame or not mainFrame:IsShown() then return end
		if updatePending then return end

		local delay = minRefreshSec
		if fastRefreshDone < maxFastRefresh then
			delay = minRefreshSecFast
			fastRefreshDone = fastRefreshDone + 1
	--		forzaUdate1=true
		end

		updatePending = true
		C_Timer.After(delay, function()
			updatePending = false
			if mainFrame and mainFrame:IsShown() then
				--print ("t"..fastRefreshDone)
				UpdateText()
			end
		end)
	end

	mainFrame = CreateFrame("Frame", addonName .. "Frame", UIParent, "BackdropTemplate")

	mainFrame:HookScript("OnShow", FuocoNoteRaiseMainFrame)
	mainFrame:HookScript("OnMouseDown", FuocoNoteRaiseMainFrame)

	mainFrame:SetScript("OnSizeChanged", function(self, w, h)
		-- SetWidth() chiama OnSizeChanged con h=nil, SetHeight() con w=nil
		w = w or self:GetWidth()
		h = h or self:GetHeight()
		if not w or not h then return end -- safety extra

		w = math.max(MINW, math.min(w, MAXW))
		h = math.max(MINH, math.min(h, MAXH))

		if text1 then
			text1:SetWidth(w - 35)
		end
		if content1 then
			content1:SetWidth(w - 35)
		end
		if questFrame then
			questFrame:SetWidth(w - 35)
			local cols = GetQuestCols(math.max(w - 35, QuestMinW))
			for _, row in ipairs(questRowPool) do
				row.frame:SetWidth(w - 35)
				for c, col in ipairs(cols) do
					if row.cells[c] then
						row.cells[c]:SetPoint("TOPLEFT", row.frame, "TOPLEFT", col.x, 0)
						row.cells[c]:SetWidth(col.w)
					end
				end
			end
		end

		if bossFrame then
			bossFrame:SetWidth(w - 35)
			local bcols = GetBossCols(math.max(w - 35, BOSS_MIN_W))
			for _, row in ipairs(bossRowPool) do
				row.frame:SetWidth(w - 35)
				for c, col in ipairs(bcols) do
					if row.cells[c] then
						row.cells[c]:SetPoint("TOPLEFT", row.frame, "TOPLEFT", col.x, 0)
						row.cells[c]:SetWidth(col.w)
					end
				end
			end
			if bossHeaderFrame then
				bossHeaderFrame:SetWidth(w - 35)
			end
		end

		if textBottom then
			textBottom:SetWidth(w - 35)
		end
		ScheduleUpdate()-- messo anche se c'e' resizeGrip:HookScript("OnMouseUp...
	end)


	if db.ShowMain then
		mainFrame:Show()
	else
		mainFrame:Hide()
	end

	----------------------------------------------------
	-- SCROLLFRAME
	----------------------------------------------------
	scrollFrame = CreateFrame("ScrollFrame", addonName .. "ScrollFrame", mainFrame, "UIPanelScrollFrameTemplate")
	scrollFrame:SetPoint("TOPLEFT", 8, -28)
	scrollFrame:SetPoint("BOTTOMRIGHT", -28, 18) -- spazio a destra per la scrollbar

	-- contenitore del testo
	content1 = CreateFrame("Frame", nil, scrollFrame)
	content1:SetSize(db.width - 40, db.height - 20) -- dimensione iniziale, verrà adattata
	scrollFrame:SetScrollChild(content1)

	-- SIMPLEHTML dentro content1
	text1 = CreateFrame("SimpleHTML", nil, content1, "InlineHyperlinkFrameTemplate") -- template con hyperlink
	text1:SetPoint("TOPLEFT", 0, 0)
	text1:SetSize(db.width - 35, db.height - 20)
	text1:EnableMouse(true)

	-- se ti serve forzare il font (dipende dal template/UI build), usa il tipo "p"
	-- text1:SetFontObject("p", "GameFontNormal")
	text1:SetFontObject("p", FuocoNoteFont) -- per il tag <p> del SimpleHTML


	-- hyperlink tooltip + click
	text1:SetScript("OnHyperlinkEnter", function(self, linkData)
		GameTooltip:SetOwner(self, "ANCHOR_CURSOR")
		GameTooltip:SetHyperlink(linkData)
		GameTooltip:Show()
	end)

	-- ── questFrame: frame reale per le righe quest ────────────────────
	questFrame = CreateFrame("Frame", nil, content1)
	questFrame:SetPoint("TOPLEFT", content1, "TOPLEFT", 0, -999) -- aggiornato da UpdateText
	questFrame:SetWidth(db.width - 35)
	questFrame:SetHeight(10)

	bossFrame = CreateFrame("Frame", nil, content1)
	bossFrame:SetPoint("TOPLEFT", content1, "TOPLEFT", 0, -999)
	bossFrame:SetWidth(db.width - 35)
	bossFrame:SetHeight(10)


	-- ── bossHeaderFrame: barra titolo sopra bossFrame ─────────────────────
	bossHeaderFrame = CreateFrame("Frame", nil, content1)
	bossHeaderFrame:SetPoint("TOPLEFT", content1, "TOPLEFT", 0, -999)
	bossHeaderFrame:SetSize(db.width - 35, 24)

	-- scritta sinistra
	local bossHeaderLabel = bossHeaderFrame:CreateFontString(nil, "OVERLAY")
	bossHeaderLabel:SetFontObject(FuocoNoteFont)
	bossHeaderLabel:SetPoint("LEFT", bossHeaderFrame, "LEFT", 4, 0)
	bossHeaderLabel:SetText(COLverde1 .. L.drop2 .. "|r   " .. (L.legenda1 or ""))

	-- bottone destra → scrolla a questFrame
	local bossHeaderBtn = CreateFrame("Button", nil, bossHeaderFrame, "UIPanelButtonTemplate")
	bossHeaderBtn:SetSize(190, 20)
	bossHeaderBtn:SetPoint("RIGHT", bossHeaderFrame, "RIGHT", -4, 0)
	bossHeaderBtn:SetText(L.vaigiu1)
	bossHeaderBtn:SetScript("OnClick", function()
		if questFrame and scrollFrame then
			local ct = content1:GetTop()
			local qt = questFrame:GetTop()
			if ct and qt then
				scrollFrame:SetVerticalScroll(math.max(0, ct - qt))
			end
		end
	end)

	-- ── textBottom: SimpleHTML per SaveInfo (sotto le righe quest) ────
	textBottom = CreateFrame("SimpleHTML", nil, content1, "InlineHyperlinkFrameTemplate")
	textBottom:SetPoint("TOPLEFT", content1, "TOPLEFT", 0, -999)
	textBottom:SetWidth(db.width - 35)
	textBottom:SetHeight(100)
	textBottom:SetFontObject("p", FuocoNoteFont)
	textBottom:EnableMouse(true)
	textBottom:Hide()

	text1:SetScript("OnHyperlinkLeave", function()
		GameTooltip:Hide()
	end)

	text1:SetScript("OnHyperlinkClick", HandleHyperlinkClick)

	text1:SetText(addonName .. " " .. L.init1)


	mainFrame:SetAlpha(db.FrameAlpha)
	local function fuoconoteUpdateAlpha()
		if not mainFrame then return end
		if mainFrame:IsMouseOver() then
			mainFrame:SetAlpha(1.0)
		else
			mainFrame:SetAlpha((db and db.FrameAlpha) or 0.6)
		end
	end

	-- parent
	--mainFrame:SetScript("OnEnter", fuoconoteUpdateAlpha)
	--mainFrame:SetScript("OnLeave", function()
	--    C_Timer.After(0.2, fuoconoteUpdateAlpha)
	--end)


	-- children che rubano il mouse
	local hoverKids = { mainFrame, scrollFrame, content1, text1 }
	for _, f in ipairs(hoverKids) do
		if f then
			f:EnableMouse(true)
			f:SetScript("OnEnter", fuoconoteUpdateAlpha)
			f:SetScript("OnLeave", function()
				C_Timer.After(0.2, fuoconoteUpdateAlpha)
			end)
		end
	end

	mainFrame:SetSize(db.width, db.height)
	mainFrame:SetPoint("TOPLEFT", UIParent, "TOPLEFT", db.posX, db.posY)

	mainFrame:SetBackdrop({
		bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
		edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
		tile = true,
		tileSize = 16,
		edgeSize = 16,
		insets = { left = 4, right = 4, top = 4, bottom = 4 }
	})
	mainFrame:SetBackdropColor(0, 0, 0, 0.8)
	mainFrame:SetBackdropBorderColor(1, 1, 1, 0.5)

	-- DRAG
	mainFrame:SetMovable(true)
	mainFrame:SetResizable(true)
	mainFrame:SetClampedToScreen(true)
	mainFrame:EnableMouse(true)
	mainFrame:RegisterForDrag("LeftButton")
	mainFrame:SetScript("OnDragStart", function(self)
		self:StartMoving()
	end)

	mainFrame:SetScript("OnDragStop", function(self)
		self:StopMovingOrSizing()
		local x = self:GetLeft()
		local y = self:GetTop() - UIParent:GetHeight() -- offset negativo da top = corretto per TOPLEFT
		self:ClearAllPoints()
		self:SetPoint("TOPLEFT", UIParent, "TOPLEFT", x, y)
		db.posX = x
		db.posY = y
	end)


	-- BARRA TITOLO (TOPRIGHT ampliato a -88 per 3 bottoni: minimizza + chiudi)
	local titleBar = CreateFrame("Frame", nil, mainFrame, "BackdropTemplate")
	titleBar:SetPoint("TOPLEFT", 5, -5)
	titleBar:SetPoint("TOPRIGHT", -88, -5) -- -88 per fare spazio a 3 bottoni (close + minimize + settings)
	titleBar:SetHeight(25)
	titleBar:SetBackdropColor(0.4, 0.2, 0, 0.8)

	titleText = titleBar:CreateFontString(nil, "OVERLAY", "GameFontNormal")
	titleText:SetFontObject(FuocoNoteFont)
	titleText:SetPoint("CENTER")
	titleText:SetText(addonName)

	-- ──────────────────────────────────────────────────────────────────
	-- MINI-BAR COLLASSATA (sostituisce la finestra quando minimizzata)
	-- ──────────────────────────────────────────────────────────────────
	collapsedBar = CreateFrame("Frame", addonName .. "CollapsedBar", UIParent, "BackdropTemplate")
	collapsedBar:SetSize(175, 30)
	collapsedBar:SetFrameStrata("HIGH")
	collapsedBar:SetMovable(true)
	collapsedBar:EnableMouse(true)
	collapsedBar:RegisterForDrag("LeftButton")
	collapsedBar:SetScript("OnDragStart", function(self) self:StartMoving() end)
	collapsedBar:SetScript("OnDragStop", function(self)
		self:StopMovingOrSizing()
		if db then
			db.collapsedX = self:GetLeft()
			db.collapsedY = self:GetTop() - UIParent:GetHeight()
		end
	end)
	collapsedBar:SetBackdrop({
		bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
		edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
		tile = true,
		tileSize = 16,
		edgeSize = 12,
		insets = { left = 3, right = 3, top = 3, bottom = 3 }
	})
	collapsedBar:SetBackdropColor(0.1, 0.05, 0, 0.92)
	collapsedBar:SetBackdropBorderColor(1, 0.65, 0, 0.9)
	collapsedBar:Hide()

	-- icona addon (stessa dell'icona minimap)
	local collapsedIcon = collapsedBar:CreateTexture(nil, "ARTWORK")
	collapsedIcon:SetSize(20, 20)
	--collapsedIcon:SetTexture("Interface\\Icons\\INV_Scroll_03")
	collapsedIcon:SetTexture("Interface\\AddOns\\" .. addonName .. "\\nota.png")
	collapsedIcon:SetTexCoord(0.07, 0.93, 0.07, 0.93)
	collapsedIcon:SetPoint("LEFT", collapsedBar, "LEFT", 5, 0)

	-- etichetta nome addon
	local collapsedLabel = collapsedBar:CreateFontString(nil, "OVERLAY")
	collapsedLabel:SetFontObject(FuocoNoteFont)
	collapsedLabel:SetPoint("LEFT", collapsedIcon, "RIGHT", 5, 0)
	collapsedLabel:SetText(addonName)

	-- bottone RIPRISTINA (+) nella mini-bar
	local restoreButton = CreateFrame("Button", nil, collapsedBar, "UIPanelButtonTemplate")
	restoreButton:SetSize(26, 22)
	restoreButton:SetPoint("RIGHT", collapsedBar, "RIGHT", -30, 0)
	restoreButton:SetText("+")
	restoreButton:SetScript("OnClick", function()
		collapsedBar:Hide()
		mainFrame:Show()
		db.ShowMain  = true
		db.minimized = false
		UpdateText()
	end)

	-- bottone CHIUDI nella mini-bar
	local collapsedCloseBtn = CreateFrame("Button", nil, collapsedBar, "UIPanelCloseButton")
	collapsedCloseBtn:SetSize(26, 26)
	collapsedCloseBtn:SetPoint("RIGHT", collapsedBar, "RIGHT", -1, 0)
	collapsedCloseBtn:SetScript("OnClick", function()
		collapsedBar:Hide()
		mainFrame:Hide()
		db.ShowMain  = false
		db.minimized = false
	end)

	-- ──────────────────────────────────────────────────────────────────
	-- BOTTONE CHIUDI principale — aggiornato: size esplicita + gestisce collapsedBar
	-- ──────────────────────────────────────────────────────────────────
	local closeButton = CreateFrame("Button", nil, mainFrame, "UIPanelCloseButton")
	closeButton:SetSize(26, 26)
	closeButton:SetPoint("TOPRIGHT", mainFrame, "TOPRIGHT", -2, -2)
	closeButton:SetScript("OnClick", function()
		collapsedBar:Hide()
		mainFrame:Hide()
		db.ShowMain  = false
		db.minimized = false
	end)

	-- ──────────────────────────────────────────────────────────────────
	-- BOTTONE MINIMIZZA — accanto al bottone chiudi
	-- ──────────────────────────────────────────────────────────────────
	local minimizeButton = CreateFrame("Button", nil, mainFrame, "UIPanelButtonTemplate")
	minimizeButton:SetSize(26, 26)
	minimizeButton:SetPoint("TOPRIGHT", closeButton, "TOPLEFT", -4, 0)
	minimizeButton:SetText("–") -- en-dash come simbolo minimizza
	minimizeButton:SetScript("OnClick", function()
		-- posiziona la mini-bar nella posizione salvata, o in alto a destra della finestra
		local cx = db.collapsedX or (mainFrame:GetRight() - 165)
		local cy = db.collapsedY or (mainFrame:GetTop() - UIParent:GetHeight())
		collapsedBar:ClearAllPoints()
		collapsedBar:SetPoint("TOPLEFT", UIParent, "TOPLEFT", cx, cy)
		mainFrame:Hide()
		collapsedBar:Show()
		db.minimized = true
		-- db.ShowMain rimane true: la finestra "esiste" ancora, è solo collassata
	end)

	-- Ripristina lo stato minimizzato al caricamento (se era minimizzata prima del reload)
	if db.minimized then
		local cx = db.collapsedX or (UIParent:GetWidth() - 170)
		local cy = db.collapsedY or -10
		collapsedBar:ClearAllPoints()
		collapsedBar:SetPoint("TOPLEFT", UIParent, "TOPLEFT", cx, cy)
		collapsedBar:Show()
		mainFrame:Hide()
	end

	-- BOTTONE SETTINGS (ingranaggio) – accanto al bottone minimizza
	local settingsButton = CreateFrame("Button", nil, mainFrame)
	settingsButton:SetSize(26, 26)
	settingsButton:SetPoint("TOPRIGHT", minimizeButton, "TOPLEFT", -4, 0)
	settingsButton:SetNormalTexture("Interface\\Buttons\\UI-OptionsButton")
	settingsButton:SetHighlightTexture("Interface\\Buttons\\UI-Common-MouseHilight", "ADD")
	settingsButton:SetPushedTexture("Interface\\Buttons\\UI-OptionsButton")
	settingsButton:GetPushedTexture():SetVertexColor(0.7, 0.7, 0.7)

	settingsButton:SetScript("OnClick", function()
		if InCombatLockdown() then return end
		if fuoconoteCategoryID and Settings and Settings.OpenToCategory then
			openedMyConfig = true
			Settings.OpenToCategory(fuoconoteCategoryID)
		end
	end)
	settingsButton:SetScript("OnEnter", function(self)
		GameTooltip:SetOwner(self, "ANCHOR_BOTTOM")
		GameTooltip:AddLine(L["Settings"] or "Impostazioni")
		GameTooltip:Show()
	end)
	settingsButton:SetScript("OnLeave", function()
		GameTooltip:Hide()
	end)

	-- HANDLE RESIZE
	local resizeGrip = CreateFrame("Button", nil, mainFrame, "PanelResizeButtonTemplate")
	resizeGrip:SetPoint("BOTTOMRIGHT", mainFrame, "BOTTOMRIGHT", -3, 3)
	-- Aggancia gli stessi script per salvare le dimensioni
	resizeGrip:HookScript("OnMouseDown", function()
		mainFrame:ClearAllPoints()
		mainFrame:SetPoint("TOPLEFT", UIParent, "TOPLEFT", db.posX, db.posY)
		mainFrame:StartSizing("BOTTOMRIGHT")
	end)
	resizeGrip:HookScript("OnMouseUp", function()
		mainFrame:StopMovingOrSizing()
		local w, h = mainFrame:GetSize()
		w = math.max(MINW, math.min(w, MAXW))
		h = math.max(MINH, math.min(h, MAXH))
		mainFrame:SetSize(w, h)
		db.width  = w
		db.height = h
		UpdateText() -- forza l'aggionamento del testo
	end)

	-- uno dei cursori standard di WoW, per il resize in basso a destra
	-- https://github.com/Gethe/wow-ui-textures/tree/live/CURSOR
	-- http://www.zezula.net/en/casc/main.html
	-- https://www.wowhead.com/it/icons
	-- SetCursor("Interface\\CURSOR\\UI-Cursor-SizeUp.blp")

	local updater = CreateFrame("Frame")
	local timeSinceLastUpdate = 0
	local timeSinceLastCheckCombact = 0

	local updater = CreateFrame("Frame")
	local timeSinceLastCheckCombact = 0
	updater:SetScript("OnUpdate", function(self, elapsed)
		timeSinceLastCheckCombact = timeSinceLastCheckCombact + elapsed
		if timeSinceLastCheckCombact > 1 then
			if mainFrame then
				local pannelloAperto = false
				if SettingsPanel:IsShown() then
					pannelloAperto = true
				end
				if db.ShowMain then
					if pannelloAperto and mainFrame:IsShown() then
						mainFrame:Hide()
					end
				end

				if db.HideInCombat and not pannelloAperto then
					if db.ShowMain and InCombatLockdown() then
						mainFrame:Hide()
						if collapsedBar then collapsedBar:Hide() end
					end
					if db.ShowMain and not InCombatLockdown() and not mainFrame:IsShown() then
						if db.minimized then
							if collapsedBar then collapsedBar:Show() end
						else
							mainFrame:Show()
							if TuttiILinkSonoCaricati == false then ScheduleUpdate() end
						end
					end
				end
			end
			timeSinceLastCheckCombact = 0
		end
	end)



	local collectionWatcher = CreateFrame("Frame")
	collectionWatcher:RegisterEvent("NEW_MOUNT_ADDED")             -- mount appreso
	collectionWatcher:RegisterEvent("NEW_TOY_ADDED")               -- toy aggiunto
	collectionWatcher:RegisterEvent("TRANSMOG_COLLECTION_UPDATED") -- illusioni/transmog
	collectionWatcher:RegisterEvent("PET_JOURNAL_LIST_UPDATE")     -- pet acquisito
	collectionWatcher:RegisterEvent("ENCOUNTER_END")               -- boss kill/wipe
	collectionWatcher:RegisterEvent("QUEST_TURNED_IN")             -- quest consegnata
	collectionWatcher:SetScript("OnEvent", function(self, event, ...)
		if event == "ENCOUNTER_END" then
			local encounterID, encounterName, difficultyID, groupSize, success = ...
			if success == 1 then -- è una kill, non un wipe
				FuocoGetKillStat(encounterID)
			end
			if db.ShowMain and not db.minimized and not InCombatLockdown() and not mainFrame:IsShown() then
				mainFrame:Show()
			end
		end
		ScheduleUpdate()
	end)


	mainFrame:HookScript("OnShow", function(self)
		PlaySound(862, "SFX")
	end)

	mainFrame:HookScript("OnHide", function(self)
		PlaySound(863, "SFX")
	end)

	local zoneAutoWatcher = CreateFrame("Frame")
	zoneAutoWatcher:RegisterEvent("ZONE_CHANGED_NEW_AREA") -- cambio zona
	--		zoneAutoWatcher:RegisterEvent("ZONE_CHANGED_INDOORS")
	--		zoneAutoWatcher:RegisterEvent("ZONE_CHANGED")
	zoneAutoWatcher:RegisterEvent("PLAYER_ENTERING_WORLD") -- reload?

	zoneAutoWatcher:SetScript("OnEvent", function(self, event)
		C_Timer.After(0.5, function()
			local mapID = C_Map.GetBestMapForUnit and C_Map.GetBestMapForUnit("player")
			if mapID and (mapID == 2594 or mapID == 2585) then
				FuocoAutoAddWaypointsForZone(mapID)
			end
		end)
	end)


	--tinsert(UISpecialFrames, addonName .. "Frame") -- no esc key
	-- print(addonName .. " caricato! /fuoconote")
end

local function FuocoNoteToggleMain()
	if not mainFrame then return end

	if db and db.minimized then
		if collapsedBar then collapsedBar:Hide() end
		mainFrame:Show()
		db.ShowMain  = true
		db.minimized = false
		UpdateText()
		return
	end

	if mainFrame:IsShown() then
		mainFrame:Hide()
		db.ShowMain = false
	else
		mainFrame:Show()
		UpdateText()
		db.ShowMain = true
	end
end

local loader = CreateFrame("Frame")
loader:RegisterEvent("ADDON_LOADED")
loader:RegisterEvent("PLAYER_ENTERING_WORLD")
loader:SetScript("OnEvent", function(self, event, name)
	if event == "ADDON_LOADED" and name == addonName then
		Initialize()
		fuoconoteCreateOptionsPanel()
		self:UnregisterEvent("ADDON_LOADED")
	elseif event == "PLAYER_ENTERING_WORLD" then
		-- init
		fuoconoteBuildEJNameByID()
		fuoconoteBuildEJBossCache()
		self:UnregisterEvent("PLAYER_ENTERING_WORLD")
		self:SetScript("OnEvent", nil)
		C_Timer.After(0, function()
			InitKilledTimes()
			if mainFrame and db then
				mainFrame:ClearAllPoints()
				mainFrame:SetPoint("TOPLEFT", UIParent, "TOPLEFT", db.posX, db.posY)
				mainFrame:SetSize(db.width, db.height) -- re-trigga OnSizeChanged → aggiorna colonne
				if mainFrame:IsShown() then
					UpdateText()
				end
			end
		end)
	end
end)


----------------------------------------------------
-- Slash Commands
----------------------------------------------------
SLASH_FUOCONOTE1 = "/fuoconote"
SLASH_FUOCONOTE2 = "/fn"

SlashCmdList["FUOCONOTE"] = function(msg)
	msg = string.lower(msg or "")

	-- /fuoconote  o /fn -> toggle UI
	if msg == "" then
		if not mainFrame then return end
		FuocoNoteToggleMain()
	elseif msg == "cfg" then
		if fuoconoteCategoryID and Settings and Settings.OpenToCategory then
			openedMyConfig = true
			Settings.OpenToCategory(fuoconoteCategoryID)
		end
	else
		print(COLrosso1 .. "[" .. addonName .. "]|r " .. L.Uso1 .. ": /fuoconote o /fn cfg")
	end
end

----------------------------------------------------
-- ICONA MINIMAP
----------------------------------------------------
local minimapButton = CreateFrame("Button", addonName .. "MinimapButton", Minimap)
minimapButton:SetSize(32, 32)
minimapButton:SetFrameStrata("MEDIUM")
minimapButton:RegisterForClicks("LeftButtonUp", "RightButtonUp")

-- sfondo rotondo standard
local overlay = minimapButton:CreateTexture(nil, "OVERLAY")
overlay:SetSize(48, 48)
overlay:SetTexture("Interface\\MINIMAP\\MiniMap-TrackingBorder")
overlay:SetPoint("TOPLEFT")

-- icona interna (metti qui la tua texture, o una di Blizzard)
local icon = minimapButton:CreateTexture(nil, "BACKGROUND")
--icon:SetTexture("Interface\\Icons\\INV_Scroll_03")
icon:SetTexture("Interface\\AddOns\\" .. addonName .. "\\nota.png")
icon:SetTexCoord(0.07, 0.93, 0.07, 0.93)
icon:SetPoint("CENTER", minimapButton, "CENTER", -1, 1)
icon:SetSize(14, 14)

-- posiziona il bottone sulla minimappa (angolo in alto a destra)
minimapButton:SetPoint("TOPRIGHT", Minimap, "TOPRIGHT", 0, 0)

-- tooltip
minimapButton:SetScript("OnLeave", function()
	GameTooltip:Hide()
end)

-- click: toggle del tuo frame principale
minimapButton:SetScript("OnClick", function(self, button)
	if button == "LeftButton" then
		FuocoNoteToggleMain()
	elseif button == "RightButton" then
		if InCombatLockdown() then
			print(COLrosso1 .. "[" .. addonName .. "]|r " .. L.NoInCombact)
			return
		end

		if fuoconoteCategoryID and Settings and Settings.OpenToCategory then
			openedMyConfig = true
			Settings.OpenToCategory(fuoconoteCategoryID)
		else
			print(COLrosso1 .. "[" .. addonName .. "]|r " .. L.NoPanel1)
		end
	end
end)

SettingsPanel:HookScript("OnHide", function()
	if not openedMyConfig then return end
	openedMyConfig = false
	C_Timer.After(0, function()
		if HideUIPanel then HideUIPanel(GameMenuFrame) end
		forzaUdate1 = true
		UpdateText()
	end)
end)

minimapButton:SetScript("OnEnter", function(self)
	GameTooltip:SetOwner(self, "ANCHOR_LEFT")
	GameTooltip:AddLine(addonName)
	GameTooltip:AddLine(L.usage1 .. " " .. addonName, 1, 1, 1)
	GameTooltip:AddLine(L.usage2 .. " " .. addonName, 1, 1, 1)
	GameTooltip:Show()
end)


-- rendi trascinabile (opzionale)
minimapButton:RegisterForDrag("LeftButton")
minimapButton:SetScript("OnDragStart", function(self)
	self:StartMoving()
end)
minimapButton:SetScript("OnDragStop", function(self)
	self:StopMovingOrSizing()
end)
minimapButton:SetMovable(true)

----------------------------------------------------
-- LibDataBroker: plugin per Titan Panel
----------------------------------------------------
local ldb = LibStub and LibStub("LibDataBroker-1.1", true)
if ldb then
	local dataObject = ldb:NewDataObject(addonName, {
		type          = "launcher",
		--icon  = "Interface\\Icons\\INV_Scroll_03",
		icon          = "Interface\\AddOns\\" .. addonName .. "\\nota.png",
		label         = addonName,
		OnClick       = function(self, button)
			if button == "LeftButton" then
				FuocoNoteToggleMain()
			elseif button == "RightButton" then
				if InCombatLockdown() then
					print(COLrosso1 .. "[" .. addonName .. "]|r " .. L.NoInCombact)
					return
				end
				if fuoconoteCategoryID and Settings and Settings.OpenToCategory then
					openedMyConfig = true
					Settings.OpenToCategory(fuoconoteCategoryID)
				end
			end
		end,
		OnTooltipShow = function(tooltip)
			if not tooltip or not tooltip.AddLine then return end
			tooltip:AddLine(addonName)
			tooltip:AddLine(L.usage1 .. " " .. addonName, 1, 1, 1)
			tooltip:AddLine(L.usage2 .. " " .. addonName, 1, 1, 1)
		end,
	})
end
----------------------------------------------------
-- sync messaggi uno solo parla (speaker election)
----------------------------------------------------
local ADDONPREFIX    = "FuocoSync"
local MSG_HELLO      = "HELLO"
local MSG_WHO        = "WHO"
local MSG_SPEAKER    = "SPEAKER:"

local lastHelloReply = 0

-- ── Controllo versione (legge la "Version" dalla TOC, niente duplicati in Lua) ──
local MSG_VER              = "VER:"
local myVersion            = (C_AddOns and C_AddOns.GetAddOnMetadata
	and C_AddOns.GetAddOnMetadata(addonName, "Version")) or "?"
local sessionLastNotified  -- fallback se db non è ancora pronto
local lastVerReply     = 0 -- throttle risposta whisper
local lastVerBroadcast = 0 -- throttle broadcast

local function SendComm(msg, dist, target)
	if not (C_ChatInfo and C_ChatInfo.SendAddonMessage) then return end
	C_ChatInfo.SendAddonMessage(ADDONPREFIX, msg, dist, target)
end

-- leaderName già dichiarato sopra nel tuo file: qui lo riusiamo come "speaker" scelto
-- local leaderName = nil

local electionActive = false
local helloSeen = {}
local pending = {}

local function NormalizeFullName(name)
	if not name or name == "" then return nil end
	if string.find(name, "-", 1, true) then return name end
	return name .. "-" .. GetRealmName()
end

local function PlayerFullName()
	local n, r = UnitFullName("player")
	if not n then return nil end
	if not r or r == "" then r = GetRealmName() end
	return n .. "-" .. r
end

local function GetAddonGroupChannel()
	local instCat = LE_PARTY_CATEGORY_INSTANCE or 2
	if IsInGroup(instCat) then
		return "INSTANCE_CHAT"
	elseif IsInRaid() then
		return "RAID"
	elseif IsInGroup() then
		return "PARTY"
	end
	return nil
end

-- Confronta versioni tipo "12.0.0710a" (numeri + suffisso lettera).
local function ParseVer(v)
	local nums, suffix = {}, ""
	for part in tostring(v or ""):gmatch("[^.]+") do
		local n, s = part:match("^(%d*)(%a*)$")
		nums[#nums + 1] = tonumber(n) or 0
		if s ~= "" then suffix = s end
	end
	return nums, suffix
end

-- ritorna 1 se a>b, -1 se a<b, 0 se uguali
local function CompareVer(a, b)
	local na, sa = ParseVer(a)
	local nb, sb = ParseVer(b)
	for i = 1, math.max(#na, #nb) do
		local x, y = na[i] or 0, nb[i] or 0
		if x ~= y then return x > y and 1 or -1 end
	end
	if sa ~= sb then return sa > sb and 1 or -1 end
	return 0
end

-- Avvisa UNA sola volta per ogni versione più recente vista (persistente in db).
-- Es.: ho la 10, esce la 11 -> avviso; resto sulla 10, esce la 12 -> avviso di nuovo.
local function MaybeNotifyVersion(theirVer)
	if not theirVer or theirVer == "" or myVersion == "?" then return end
	if CompareVer(theirVer, myVersion) ~= 1 then return end -- non più recente della mia
	local lastNotified = (db and db.lastNotifiedVersion) or sessionLastNotified or "0"
	if CompareVer(theirVer, lastNotified) ~= 1 then return end -- già avvisato per questa o superiore
	sessionLastNotified = theirVer
	if db then db.lastNotifiedVersion = theirVer end
	StaticPopup_Show("FUOCONOTE_NEWVER", theirVer, myVersion)
end

-- Annuncia la mia versione a gruppo/raid E gilda (con throttle anti-spam).
local function BroadcastVersion()
	if not (C_ChatInfo and C_ChatInfo.SendAddonMessage) or myVersion == "?" then return end
	local now = GetTime and GetTime() or 0
	if now - lastVerBroadcast < 30 then return end
	lastVerBroadcast = now
	local chan = GetAddonGroupChannel()
	if chan then C_ChatInfo.SendAddonMessage(ADDONPREFIX, MSG_VER .. myVersion, chan) end
	if IsInGuild() then C_ChatInfo.SendAddonMessage(ADDONPREFIX, MSG_VER .. myVersion, "GUILD") end
end

StaticPopupDialogs["FUOCONOTE_NEWVER"] = {
	text = (L and L.nuovaVersione1) or "FuocoNote: new version %s available (you have %s)",
	button1 = OKAY,
	timeout = 0,
	whileDead = true,
	hideOnEscape = true,
	preferredIndex = 3,
}

local function GetRosterUnitsInOrder()
	local units = {}
	if IsInRaid() then
		local n = GetNumGroupMembers()
		for i = 1, n do units[#units + 1] = "raid" .. i end
	elseif IsInGroup() then
		units[#units + 1] = "player"
		local n = GetNumSubgroupMembers()
		for i = 1, n do units[#units + 1] = "party" .. i end
	else
		units[#units + 1] = "player"
	end
	return units
end

local function PickSpeaker()
	local units = GetRosterUnitsInOrder()

	-- 1) se il vero leader è tra chi ha risposto HELLO, preferiscilo
	local leaderCandidate = nil
	for _, unit in ipairs(units) do
		if UnitExists(unit) and UnitIsGroupLeader(unit) then
			local n, r = UnitFullName(unit)
			if n then
				if not r or r == "" then r = GetRealmName() end
				leaderCandidate = n .. "-" .. r
			end
			break
		end
	end
	if leaderCandidate and helloSeen[leaderCandidate] then
		return leaderCandidate
	end

	-- 2) altrimenti: candidato deterministico tra chi ha l'addon (minimo alfabetico).
	--    NON usare l'ordine del roster: in party i token ("player"/"partyN") sono
	--    relativi al client, quindi ognuno eleggerebbe sé stesso -> messaggi duplicati.
	--    Il min alfabetico su helloSeen è invece uguale per tutti i client.
	local best
	for full in pairs(helloSeen) do
		if not best or full < best then best = full end
	end
	return best
end

local function ClearTable(t)
	for k in pairs(t) do t[k] = nil end
end

-- Invia i messaggi accodati SOLO se sono lo speaker, poi svuota sempre la coda.
-- (i non-speaker scartano la propria coda: parla solo lo speaker)
local function FlushPendingIfSpeaker()
	local me = PlayerFullName()
	if leaderName and me and me == leaderName then
		for i = 1, #pending do
			local m = pending[i]
			C_ChatInfo.SendChatMessage(m.text, m.chan)
		end
	end
	ClearTable(pending)
end

local FuocoSync = CreateFrame("Frame")
FuocoSync:RegisterEvent("GROUP_ROSTER_UPDATE")
FuocoSync:RegisterEvent("PLAYER_ENTERING_WORLD")
FuocoSync:RegisterEvent("GROUP_LEFT")
FuocoSync:RegisterEvent("GROUP_JOINED")
FuocoSync:RegisterEvent("GUILD_ROSTER_UPDATE")
FuocoSync:RegisterEvent("CHAT_MSG_ADDON")

-- IMPORTANTE: registra il prefix addon
if C_ChatInfo and C_ChatInfo.RegisterAddonMessagePrefix then
	C_ChatInfo.RegisterAddonMessagePrefix(ADDONPREFIX)
end

function FuocoSync:Reset()
	ClearTable(helloSeen)
	ClearTable(pending)
	electionActive = false
	leaderName = nil
end

function FuocoSync:StartElection()
	if electionActive then return end

	if not (IsInGroup() or IsInRaid()) then
		leaderName = PlayerFullName()
		if ScheduleUpdate then ScheduleUpdate() end
		return
	end

	electionActive = true
	leaderName = nil -- durante l'elezione i messaggi si accodano invece di essere scartati
	ClearTable(helloSeen)

	local me = PlayerFullName()
	if me then helloSeen[me] = true end

	local chan = GetAddonGroupChannel()
	if chan and C_ChatInfo and C_ChatInfo.SendAddonMessage and db.SayGZ then
		C_ChatInfo.SendAddonMessage(ADDONPREFIX, MSG_HELLO, chan)
	end

	C_Timer.After(1.0, function()
		leaderName = PickSpeaker()
		local me = PlayerFullName()
		local chan = GetAddonGroupChannel()
		if leaderName and me and leaderName == me and chan then
			SendComm(MSG_SPEAKER .. leaderName, chan)
		end
		electionActive = false

		-- flush coda: solo lo speaker manda i messaggi accumulati
		FlushPendingIfSpeaker()

		-- aggiorna la barra con lo speaker appena eletto
		if ScheduleUpdate then ScheduleUpdate() end
	end)
end

function FuocoSync:SendSyncedMessage(text, chatChannel)
	-- fuori gruppo: manda normalmente
	if not (IsInGroup() or IsInRaid()) then
		C_ChatInfo.SendChatMessage(text, "SAY")
		--C_ChatInfo.SendChatMessage(text, chatChannel or "SAY")
		return
	end

	-- se ancora non sappiamo lo speaker, accoda e avvia elezione
	if not leaderName then
		pending[#pending + 1] = { text = text, chan = chatChannel }

		local chan = GetAddonGroupChannel()
		if chan then
			SendComm(MSG_WHO, chan)   -- chiede allo speaker di presentarsi
			SendComm(MSG_HELLO, chan) -- presence (utile se non c’è speaker ancora)
		end

		FuocoSync:StartElection()
		return
	end

	-- parla solo lo speaker
	local me = PlayerFullName()
	if not me or me ~= leaderName then return end

	C_ChatInfo.SendChatMessage(text, chatChannel)
end

FuocoSync:SetScript("OnEvent", function(self, event, prefix, message, channel, sender)
	if event == "CHAT_MSG_ADDON" and prefix == ADDONPREFIX then
		local s = NormalizeFullName(sender)

		if message == MSG_HELLO then
			if s then helloSeen[s] = true end

			-- Rispondi HELLO (throttle) così chi ha reload ricostruisce la lista
			local now = GetTime and GetTime() or 0
			if now - lastHelloReply > 2 then
				local chan = GetAddonGroupChannel()
				if chan then SendComm(MSG_HELLO, chan) end
				lastHelloReply = now
			end

			-- Se io sono lo speaker, dico subito allo specifico sender chi è lo speaker (whisper)
			local me = PlayerFullName()
			if leaderName and me and me == leaderName and sender then
				SendComm(MSG_SPEAKER .. leaderName, "WHISPER", sender)
			end
			return
		end

		if message == MSG_WHO then
			local me = PlayerFullName()
			if leaderName and me and me == leaderName and sender then
				SendComm(MSG_SPEAKER .. leaderName, "WHISPER", sender)
			end
			return
		end

		if type(message) == "string" and message:sub(1, #MSG_SPEAKER) == MSG_SPEAKER then
			local claimed = NormalizeFullName(message:sub(#MSG_SPEAKER + 1))
			if claimed and claimed ~= "" then
				leaderName = claimed
				electionActive = false

				-- se io sono lo speaker svuoto la coda, altrimenti la scarto
				FlushPendingIfSpeaker()

				-- aggiorna la barra con lo speaker comunicato
				if ScheduleUpdate then ScheduleUpdate() end
			end
			return
		end

		if type(message) == "string" and message:sub(1, #MSG_VER) == MSG_VER then
			local theirVer = message:sub(#MSG_VER + 1)
			local cmp = CompareVer(theirVer, myVersion)
			if cmp == 1 then
				MaybeNotifyVersion(theirVer) -- lui è più aggiornato: avvisami
			elseif cmp == -1 and sender then
				-- lui è più vecchio: gli mando la mia versione (throttle) così viene avvisato
				local now = GetTime and GetTime() or 0
				if now - lastVerReply > 5 then
					lastVerReply = now
					SendComm(MSG_VER .. myVersion, "WHISPER", sender)
				end
			end
			return
		end
	end

	if event == "GROUP_LEFT" then
		FuocoSync:Reset()
		leaderName = PlayerFullName() -- da solo lo speaker sono io
		if ScheduleUpdate then ScheduleUpdate() end
		return
	end

	if event == "GUILD_ROSTER_UPDATE" then
		BroadcastVersion()
		return
	end

	if event == "PLAYER_ENTERING_WORLD" or event == "GROUP_JOINED" or event == "GROUP_ROSTER_UPDATE" then
		BroadcastVersion()
		if IsInGroup() or IsInRaid() then
			self:StartElection()
		else
			leaderName = PlayerFullName()
			if ScheduleUpdate then ScheduleUpdate() end
		end
		return
	end
end)

----------------------------------------------------
-- GZ
----------------------------------------------------
for _, id in ipairs(tabellaLoot) do
	lootSet[id] = true
end

-- aggiungi tutti gli item presenti nei dropIDs di droplist
for _, item1 in ipairs(droplist) do
	local dropIDs = item1[4] -- il 5° campo è la tabella di itemID
	if dropIDs then
		for _, itemID in ipairs(dropIDs) do
			if type(itemID) == "number" then
				lootSet[itemID] = true
			end
		end
	end
end

for _, questData in ipairs(IDQuest) do -- itera direttamente su IDQuest
	local dropIDs = questData.drop     -- campo drop (4° elemento)
	if dropIDs then
		for _, itemID in ipairs(dropIDs) do
			if type(itemID) == "number" then
				lootSet[itemID] = true -- aggiunge tutti i drop a lootSet
			end
		end
	end
end

local lootWatcher = CreateFrame("Frame")
lootWatcher:RegisterEvent("CHAT_MSG_LOOT")

lootWatcher:SetScript("OnEvent", function(self, event, msg, playerName, ...)
	if event == "CHAT_MSG_LOOT" then
		if issecretvalue(msg) then
			--print('??secret??')
			return
		end
		local itemLink = msg:match("(|cnIQ%x:|Hitem:.-|h%[.-%]|h|r)") or
			msg:match("(|cff%x%x%x%x%x%x|Hitem:.-|h%[.-%]|h|r)")
		--_G["ChatFrame"..tostring(id_chat)]:AddMessage(COLverde2.."debug 2|r "..itemLink) -- non usare
		if not itemLink then return end

		local itemID = tonumber(itemLink:match("item:(%d+):"))
		if not itemID then
			_G["ChatFrame" .. tostring(id_chat)]:AddMessage(COLrosso1 .. "debug 3 |r PRE NOID!!!")
		end
		if not itemID or not lootSet[itemID] then return end
		--_G["ChatFrame"..tostring(id_chat)]:AddMessage(COLverde2.."debug 4|r post itemID:".. itemID.. " tracked=".. tostring(lootSet[itemID]))
		local shortName = playerName:match("([^%-]+)") or playerName -- solo Nome senza -Reame
		if shortName == '' then
			-- dovrebbe essere richiesta di roll ??
			--print('---- shortName vuoto uso playerName')
			--return
			shortName=playerName
		end
		local msgParty = string.format(addonName .. " Collector: " .. L.gzz1, shortName, itemLink)

		if shortName == nome_pg then
			msgParty = string.format(addonName .. " Collector: " .. L.gzz2, itemLink)
		end
		if shortName == '' then
			msgParty = string.format(addonName .. " Collector: " .. L.gzz3, itemLink)
		end


		-- scegli canale gruppo/raid
		local chan = nil
		if IsInGroup(LE_PARTY_CATEGORY_INSTANCE) then
			chan = "INSTANCE_CHAT"
		elseif IsInRaid() then
			chan = "RAID"
		elseif IsInGroup() then
			chan = "PARTY"
		else
			--chan = nil
			chan = "SAY"
		end
--print('chan '..chan)
--print('lead '..leaderName)

		_G["ChatFrame" .. tostring(id_chat)]:AddMessage(COLrosso1 .. L.attenzione .. " |r" .. msgParty)
		print(COLrosso1 .. L.attenzione .. " |r" .. msgParty)

		if chan then
			--SendChatMessage(msgParty, chan)
			if db.SayGZ then
				_G["ChatFrame" .. tostring(id_chat)]:AddMessage(COLverde2 .. "GZGZGZ1|r")
				FuocoSync:SendSyncedMessage(msgParty, chan)
			end
		end
	end
end)


local function fuoconoteBuildStatNameCache()
	if StatNameCacheBuilt then return end
	if not GetStatisticsCategoryList or not GetCategoryNumAchievements or not GetAchievementInfo then
		return
	end

	wipe(StatNameByID)

	for _, catID in pairs(GetStatisticsCategoryList()) do
		local numStats = GetCategoryNumAchievements(catID) or 0
		for i = 1, numStats do
			local id, nome = GetAchievementInfo(catID, i)
			if id and nome and nome ~= "" then
				StatNameByID[id] = nome
			end
		end
	end

	StatNameCacheBuilt = true
end

FuocoGetKillStat = function(encounterID)
	InitKilledTimes()
	--https://wago.tools/db2/JournalEncounter >> DungeonEncounterID
	--		local entry = nil
	--		for _, item in ipairs(droplist) do
	--		    if item.encounterID == encounterID then
	--		        entry = item
	--		        break
	--		    end
	--		end
	--		if not entry then return end  -- boss non tracciato in droplist
	--		InitKilledTimes()
end

local function getIDs(statID)
	if type(statID) == "number" then
		return { statID }
	elseif type(statID) == "table" then
		return statID
	end
	return {}
end

InitKilledTimes = function()
	if not db then return end
	db.killedTimes = db.killedTimes or {}

	fuoconoteBuildStatNameCache()

	-- Salva un valore per ogni ID in db.killedTimes
	for _, item in ipairs(droplist) do
		for _, id in ipairs(getIDs(item.statID)) do
			db.killedTimes[id] = GetStatistic(id) or 0
		end
	end

	-- Calcola conteggioKill e statName sommando tutti gli ID di item.statID
	-- su tutti i personaggi/realm
	for _, item in ipairs(droplist) do
		local ids = getIDs(item.statID)
		item.statName = nil

		if #ids > 0 then
			local totale = 0
			local statNames = {}

			for _, id in ipairs(ids) do
				local nome = StatNameByID[id]
				if nome and nome ~= "" then
					table.insert(statNames, nome)
				end
			end

			for _, realmData in pairs(FuocoNoteDB) do
				for _, charData in pairs(realmData) do
					if charData.killedTimes then
						for _, id in ipairs(ids) do
							totale = totale + (tonumber(charData.killedTimes[id]) or 0)
						end
					end
				end
			end
			
			item.conteggioKill = totale
			if #statNames > 0 then
				item.statName = table.concat(statNames, " / ")
			end
		else
			item.conteggioKill = nil
		end
	end

	ScheduleUpdate()
end


----------------------------------------------------
-- Auto-waypoint: aggiunge i waypoint TomTom
-- di ogni quest in IDQuest per la zona corrente
----------------------------------------------------
FuocoAutoAddWaypointsForZone = function(mapID)
	if not mapID then return end
	for _, quest in ipairs(IDQuest) do
		local idzona = quest.idzona
		local isInZone = false
		if type(idzona) == "table" then
			for _, zid in ipairs(idzona) do
				if zid == mapID then
					isInZone = true; break
				end
			end
		elseif idzona == mapID then
			isInZone = true
		end
		if isInZone and quest.note then
			local alreadyDone = false
			if quest.drop and #quest.drop > 0 then
				alreadyDone = true
				for _, itemID in ipairs(quest.drop) do
					if type(itemID) == "number"
						and not fuoconoteIsCollectibleOwned(itemID) then
						alreadyDone = false; break
					end
				end
			end
			if not alreadyDone then
				-- Nuovo pattern: cattura fra |Hfuoconoteway e |h
				for payload in quest.note:gmatch("|Hfuoconoteway(.-)%|h") do
					local noteMap, coords, tipo, idPassato =
						FuocoWayParseLink(payload)
					if noteMap == mapID then
						local title = FuocoWayGetTitle(tipo, idPassato)
						for x1, y1 in
						(coords or ""):gmatch("(%d+%.?%d*)%s+(%d+%.?%d*)")
						do
							local x, y
							x, y = tonumber(x1), tonumber(y1)
							if x and y then
								FuocoWayAddPoint(mapID, x / 100, y / 100, title)
							end
						end
					end
				end
				if TomTom and TomTom.SetClosestWaypoint then
					TomTom:SetClosestWaypoint()
				end
			end
		end
	end
end
