local _, LK = ...

local HBD = LibStub("HereBeDragons-2.0");
local HBDPins = LibStub("HereBeDragons-Pins-2.0");
local LOREKEEPER_MAP_PIN_TEXTURE = "Interface\\AddOns\\Lorekeeper\\Assets\\Textures\\LorekeeperScroll_Closed.png";

-- Using Blizz's globally accessible frame fade function causes taint with the map
-- So just add their own code in locally

local FrameFaderDriver;
local fadingFrames;
local deferredFadingFrames;

-- adding these here so they can be accessed earlier
local ItemDataProvider;
local ItemScrollBox;

local defaultTTSSettings = {
	queuePages = false,
	volume = 50,
	speed = 0,
	phonetics = true,
};

local function OnUpdate(self, elapsed)
	local isMoving = IsPlayerMoving();
	for frame, setting in pairs(fadingFrames) do
		local fadeOut = isMoving and (not setting.fadePredicate or setting.fadePredicate());
		frame:SetAlpha(DeltaLerp(frame:GetAlpha(), fadeOut and setting.minAlpha or setting.maxAlpha, .1, elapsed));
	end
end

local function MergeDeferredEvents()
	if deferredFadingFrames then
		for frame, setting in pairs(deferredFadingFrames) do
			fadingFrames[frame] = setting;
		end
		deferredFadingFrames = nil;
	end
end

local function OnEvent(self, event, ...)
	if event == "PLAYER_STARTED_MOVING" 
	or event == "PLAYER_STOPPED_MOVING" 
	or event == "PLAYER_IS_GLIDING_CHANGED" 
	or event == "PLAYER_IMPULSE_APPLIED" then
		MergeDeferredEvents();
	end
end

local function InitializeDriver()
	if not FrameFaderDriver then
		fadingFrames = {};

		FrameFaderDriver = CreateFrame("FRAME");
		FrameFaderDriver:SetScript("OnUpdate", OnUpdate);
		FrameFaderDriver:SetScript("OnEvent", OnEvent);
		FrameFaderDriver:RegisterEvent("PLAYER_STARTED_MOVING");
		FrameFaderDriver:RegisterEvent("PLAYER_STOPPED_MOVING");
		FrameFaderDriver:RegisterEvent("PLAYER_IS_GLIDING_CHANGED");
		FrameFaderDriver:RegisterEvent("PLAYER_IMPULSE_APPLIED");
	end
end

local function PackFadeData(minAlpha, maxAlpha, durationSec, fadePredicate)
	return { minAlpha = minAlpha or .5, maxAlpha = maxAlpha or 1, durationSec = durationSec or 1, fadePredicate = fadePredicate };
end

local function RemoveFrameInternal(frame)
	if fadingFrames then
		fadingFrames[frame] = nil;
	end
	if deferredFadingFrames then
		deferredFadingFrames[frame] = nil;
	end
end

local PlayerMovementFrameFader = {};

function PlayerMovementFrameFader.AddFrame(frame, minAlpha, maxAlpha, durationSec, fadePredicate)
	RemoveFrameInternal(frame);

	InitializeDriver();
	fadingFrames[frame] = PackFadeData(minAlpha, maxAlpha, durationSec, fadePredicate);
end

-- The fading won't take effect until the player stops or starts moving again
function PlayerMovementFrameFader.AddDeferredFrame(frame, minAlpha, maxAlpha, durationSec, fadePredicate)
	InitializeDriver();
	RemoveFrameInternal(frame);

	if not deferredFadingFrames then
		deferredFadingFrames = {};
	end
	deferredFadingFrames[frame] = PackFadeData(minAlpha, maxAlpha, durationSec, fadePredicate);
end

function PlayerMovementFrameFader.RemoveFrame(frame)
	local maxAlpha = fadingFrames and fadingFrames[frame] and fadingFrames[frame].maxAlpha;
	if maxAlpha then
		frame:SetAlpha(maxAlpha);
	end

	RemoveFrameInternal(frame, restoreAlpha);
end

local function SetupFade(self)
	local minAlpha = 0.5;
	local maxAlpha = 1.0;
	local duration = 0.5;
	local predicate = function() return not self:IsMouseOver(); end;
	PlayerMovementFrameFader.AddDeferredFrame(self, minAlpha, maxAlpha, duration, predicate);
end

local function CleanupFade(self)
	PlayerMovementFrameFader.RemoveFrame(self);
end

local function moveFrameXY(frame, point, relativePoint, newxOfs, newyOfs)
	local point_, relativeTo, relativePoint_, xOfs, yOfs = frame:GetPoint();
	point, relativeTo, relativePoint, xOfs, yOfs = point, relativeTo, relativePoint, xOfs+newxOfs, yOfs+newyOfs;
	frame:SetPoint(point, relativeTo, relativePoint, xOfs, yOfs);
end

local function Print(...)
	if not ... then
		if LoreK_DB["settings"]["debugAdvanced"] then
			Print("Something failed spectacularly, the data in Print was nil");
		end
		return
	end
	local prefix = string.format("|cFFFFF569".. Lorekeeper_API.LK["Lorekeeper"] .. "|r:");
	DEFAULT_CHAT_FRAME:AddMessage(string.join(" ", prefix, ...));
end

local PH_PLAYER_NAME = "$PLAYER_NAME$";
local PH_PLAYER_CLASS = "$PLAYER_CLASS$";

local function ReverseNameAndClass(pageText)
	local name = UnitName("player");
	local class = UnitClass("player");
	pageText = pageText:gsub("%$PLAYER_NAME%$", name);
	pageText = pageText:gsub("%$PLAYER_CLASS%$", class);
	return pageText;
end

-- Function to replace words with their phonetic equivalents
local function replaceWithPhonetics(text)
	if not LK["Phonetics"] then return text end
	if not LoreK_DB.settings.TTSSettings.phonetics then return text end
	return text:gsub("[%w']+", function(word)
		local lowerWord = word:lower()

		-- Check if the word itself is in the phoneticTable
		if LK["Phonetics"][lowerWord] then
			return LK["Phonetics"][lowerWord]

		-- Check for possessive form (word ending with 's)
		elseif lowerWord:sub(-2) == "'s" then
			local baseWord = lowerWord:sub(1, -3) -- Remove the 's for lookup
			if LK["Phonetics"][baseWord] then
				return LK["Phonetics"][baseWord] .. "'s" -- Append the 's to the phonetic replacement
			end
		end

		-- If no replacement found, return the original word
		return word
	end)
end

local TRP3Replacements = {
	-- Center aligned headers and paragraphs
	["<h1%s+align=\"center\">"] = "{h1:c}",
	["<h2%s+align=\"center\">"] = "{h2:c}",
	["<h3%s+align=\"center\">"] = "{h3:c}",
	["<p%s+align=\"center\">"] = "{p:c}",
	["</p>"] = "{/p}",
	["<p>"] = "{p}",
	["</h1>"] = "{/h1}",
	["<h1>"] = "{h1}",
	["</h2>"] = "{/h2}",
	["<h2>"] = "{h2}",
	["</h3>"] = "{/h3}",
	["<h3>"] = "{h3}",

	-- Left aligned
	["<h1%s+align=\"left\">"] = "{h1:l}",
	["<h2%s+align=\"left\">"] = "{h2:l}",
	["<h3%s+align=\"left\">"] = "{h3:l}",
	["<p%s+align=\"left\">"] = "{p:l}",

	-- Right aligned
	["<h1%s+align=\"right\">"] = "{h1:r}",
	["<h2%s+align=\"right\">"] = "{h2:r}",
	["<h3%s+align=\"right\">"] = "{h3:r}",
	["<p%s+align=\"right\">"] = "{p:r}",

	-- Generic tags
	["<html>"] = "",
	["</html>"] = "",
	["<body>"] = "",
	["</body>"] = "",
	["<br/>"] = "\n",
	["<hr/>"] = "\n",

	-- Handle combined closing tags
	["</body></html>"] = "",
	["<html><body>"] = "",
};


local function replaceImageTags(inputText)
	inputText = inputText:gsub(
		'<img ([^>]-)/>',
		function(attributes)
			local src = attributes:match('src="(.-)"') or "";
			
			local width = attributes:match('width="(%d+)"') or 512;
			local height = attributes:match('height="(%d+)"') or 256;
			
			-- Extract the align, and map it to shorthand
			local align = attributes:match('align="(.-)"') or "";
			local alignMap = { ["center"] = "c", ["left"] = "l", ["right"] = "r" };
			local alignShort = alignMap[align] or "";
			
			-- Return the formatted replacement
			return string.format("{img:%s:%s:%s:%s}", src, width, height, alignShort);
		end
	)
	return inputText;
end

local function replaceHTMLTags(tag, replacementsTable)
	local lowerTag = tag:lower();

	for pattern, replacement in pairs(replacementsTable) do
		lowerTag = lowerTag:gsub(pattern, replacement);
	end

	return lowerTag;
end

local function TRP3HTMLConvert(text)
	if not text then return end

	text = text:gsub("(<[^>]+>)", function(tag) 
		return replaceHTMLTags(tag, TRP3Replacements);
	end)

	text = replaceImageTags(text);

	return text;
end



-- Sort items in a list
local filteredItems = {};

local allData = {};

 -- Map Pins
local mapPinFramePool = {};
local mapPinFramesActive = {};

local function AcquireMapPin()
	local pin = table.remove(mapPinFramePool)
	if not pin then
		pin = CreateFrame("Frame");
		pin:EnableMouse(true);
		pin.tex = pin:CreateTexture(nil, "OVERLAY");
		pin.tex:SetAllPoints();
	end
	pin:Show();
	tinsert(mapPinFramesActive, pin);
	return pin;
end

local function ReleasePins()
	for _, pin in ipairs(mapPinFramesActive) do
		pin:Hide();
		tinsert(mapPinFramePool, pin);
	end
	wipe(mapPinFramesActive);
end

local function RefreshMapPins()
	HBDPins:RemoveAllWorldMapIcons("Lorekeeper");
	ReleasePins();

	if not LoreK_DB or not LoreK_DB["settings"] then return end;
	if LoreK_DB["settings"]["hideAllPins"] then return end;
	if not allData then return end;

	local showCollected = LoreK_DB["settings"]["showCollectedPins"];

	for itemID, data in pairs(allData) do
		local base = data["base"];
		if base then
			local mapData = base["mapData"];
			if mapData then
				local hasRead = base["hasRead"];

				if not hasRead or showCollected then
					local title = base["title"] or itemID;

					for mapID, coords in pairs(mapData) do
						local x, y = coords[1], coords[2];
						if x and y and C_Map.GetMapInfo(mapID) then
							local pin = AcquireMapPin();
							pin:SetSize(20, 20);
							pin.tex:SetTexture(LOREKEEPER_MAP_PIN_TEXTURE);

							if hasRead then
								pin.tex:SetVertexColor(0.6, 0.6, 0.6, 0.85);
								pin.tex:SetDesaturated(true);
							else
								pin.tex:SetVertexColor(1, 1, 1, 1);
								pin.tex:SetDesaturated(false);
							end

							local capturedTitle = title;
							local capturedRead = hasRead;
							local capturedItemID = itemID;
							local capturedMapID = mapID;
							local capturedX = x;
							local capturedY = y;

							pin:SetScript("OnEnter", function(self)
								GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
								GameTooltip:AddLine(capturedTitle, 1, 1, 1);
								if capturedRead then
									GameTooltip:AddLine(LK["Collected"], 0, 1, 0);
								else
									GameTooltip:AddLine(LK["NotCollected"], 1, 0.65, 0);
								end
								GameTooltip:Show();
							end)
							pin:SetScript("OnLeave", function()
								GameTooltip:Hide();
							end)
							pin:SetScript("OnMouseDown", function(self, button)
								if IsControlKeyDown() then
									WorldMapFrame:Show();
									WorldMapFrame:SetMapID(capturedMapID);
									C_Map.SetUserWaypoint(UiMapPoint.CreateFromVector2D(capturedMapID, CreateVector2D(capturedX, capturedY)));
									C_SuperTrack.SetSuperTrackedUserWaypoint(true);
									PlaySound(170270);
								else
									LK.LoreKGUI.SelectAndShowEntry(capturedItemID);
								end
							end)

							HBDPins:AddWorldMapIconMap(
								"Lorekeeper", pin,
								mapID, x, y,
								HBD_PINS_WORLDMAP_SHOW_PARENT
							);
						end
					end
				end
			end
		end
	end
end

LK.RefreshMapPins = RefreshMapPins;

local function insertItems(dataSource, searchText)
	for itemID, itemData in pairs(dataSource) do
		if dataSource[itemID]["base"] and dataSource[itemID]["base"]["title"] then
			local title = dataSource[itemID]["base"]["title"];
			if title:lower():find(searchText) then
				local isFavorite = dataSource[itemID]["base"]["isFavorite"] or false;
				table.insert(filteredItems, {itemID = itemID, title = title, isFavorite = isFavorite});
			end
		end
	end
end

--------------------------------------------------------------------------

--------------------------------------------------------------------------

-- Create the main frame
local LoreKGUI = CreateFrame("Frame", "LoreKMainframe", UIParent, "PortraitFrameTemplateMinimizable");
LK["LoreKGUI"] = LoreKGUI
tinsert(UISpecialFrames, LoreKGUI:GetName());
LK.LoreKGUI = LoreKGUI;
LoreKGUI:SetPortraitTextureRaw("Interface\\AddOns\\Lorekeeper\\Assets\\Textures\\LorekeeperScroll_BG.png");
LoreKGUI:SetSize(703, 606);
LoreKGUI:SetPoint("CENTER", UIParent, "CENTER");
LoreKGUI:SetClampedToScreen(true);
LoreKGUI:SetMovable(true);
LoreKGUI:EnableMouse(true);
LoreKGUI:RegisterForDrag("LeftButton");
LoreKGUI:SetScript("OnDragStart", LoreKGUI.StartMoving);
LoreKGUI:SetScript("OnDragStop", LoreKGUI.StopMovingOrSizing);
LoreKGUI:SetTitle(LK["Lorekeeper"]);
LoreKGUI:SetFrameStrata("MEDIUM");
LoreKGUI:Hide();
LoreKGUI:SetScript("OnMouseDown", function(self) self:SetToplevel(true); end);

LoreKGUI:SetResizable(true);

LoreKGUI:SetResizeBounds(703, 606, 1618, 883); 

LoreKGUI.resizeHandle = CreateFrame("Button", nil, LoreKGUI);
LoreKGUI.resizeHandle:SetPoint("BOTTOMRIGHT", LoreKGUI, "BOTTOMRIGHT", 10, -8);
LoreKGUI.resizeHandle:SetSize(64, 64);

LoreKGUI.resizeHandle:SetNormalAtlas("damagemeters-scalehandle");
LoreKGUI.resizeHandle:SetPushedAtlas("damagemeters-scalehandle-pressed");
LoreKGUI.resizeHandle:SetHighlightAtlas("damagemeters-scalehandle-hover");

LoreKGUI.resizeHandle:SetScript("OnMouseDown", function(self, button)
	if button == "LeftButton" then
		LoreKGUI:StartSizing("BOTTOMRIGHT");
	end
end);

LoreKGUI.resizeHandle:SetScript("OnMouseUp", function(self, button)
	LoreKGUI:StopMovingOrSizing();
end);

local HolidaysTheme = {};
HolidaysTheme.Header = CreateFrame("Frame", nil, LoreKGUI);
HolidaysTheme.Header.Resize = .56
HolidaysTheme.Header:SetPoint("CENTER", LoreKGUI, "TOP", 45, -2);
HolidaysTheme.Header:SetSize(2048*HolidaysTheme.Header.Resize,256*HolidaysTheme.Header.Resize);
HolidaysTheme.Header:SetFrameLevel(LoreKGUI.TitleContainer:GetFrameLevel()+50);
HolidaysTheme.Header.tex = HolidaysTheme.Header:CreateTexture(nil, "ARTWORK", nil, 1);
HolidaysTheme.Header.tex:SetAllPoints(true);
HolidaysTheme.Header.tex:SetTexture("Interface\\AddOns\\Lorekeeper\\Assets\\Textures\\HallowsEndTop");

HolidaysTheme.Bottom = CreateFrame("Frame", nil, LoreKGUI);
HolidaysTheme.Bottom:SetSize(565,570);
HolidaysTheme.Bottom:SetFrameLevel(LoreKGUI.TitleContainer:GetFrameLevel()+50);
HolidaysTheme.Bottom.tex = HolidaysTheme.Bottom:CreateTexture(nil, "ARTWORK", nil, 2);
HolidaysTheme.Bottom.tex:SetAllPoints(true);
HolidaysTheme.Bottom.tex:SetAtlas("perks-theme-hallowsend-tl-box");

local function GetHoliday()
	local numEvents = C_Calendar.GetNumDayEvents(0, C_DateAndTime.GetCurrentCalendarTime().monthDay);

	for i = 1, numEvents do
		local event = C_Calendar.GetHolidayInfo(0, C_DateAndTime.GetCurrentCalendarTime().monthDay, i);
		
		if event and event.name == LK["Holiday_HallowsEnd"] then
			HolidaysTheme.Header.tex:SetTexture("Interface\\AddOns\\Lorekeeper\\Assets\\Textures\\HallowsEndTop");
			HolidaysTheme.Bottom.tex:SetTexture("Interface\\AddOns\\Lorekeeper\\Assets\\Textures\\HallowsEndBottom");
			return true;
		elseif event and event.name == LK["Holiday_WinterVeil"] then
			HolidaysTheme.Header.tex:SetTexture("Interface\\AddOns\\Lorekeeper\\Assets\\Textures\\WinterVeilTop");
			HolidaysTheme.Bottom.tex:SetTexture("Interface\\AddOns\\Lorekeeper\\Assets\\Textures\\WinterVeilBottom");
			return true;
		end
	end
end

local function HideHolidays()
	for k, v in pairs(HolidaysTheme) do
		v:Hide();
	end
end
HideHolidays();

local function ToggleHolidays()
	if GetHoliday() and LoreK_DB["settings"]["holidayThemes"] then
		for k, v in pairs(HolidaysTheme) do
			v:Show();
		end
	else
		HideHolidays();
	end
end


local MeowFrameMixin = {};

MeowFrameMixin.SoundFileList = {
	3598607, 3598611, 3598615, 3598605,
	3598609, 3598613, 3598617, 3598619,
	3598621, 3598623, 3598625, 3598641,
	3598639, 3598635, 3598637, 3598611,
};

function MeowFrameMixin:OnLoad()
	self.clickCount = 0;
	self.clickThreshold = 20;
	self.timeFrame = .2;
	self.lastClickTime = 0;

	self:RegisterForClicks("AnyDown", "AnyUp");
end

function MeowFrameMixin:OnClick(_, down)
	local portrait = LoreKGUI.PortraitContainer.portrait;
	local currentTime = GetTime();

	if not down then
		portrait:SetTexCoord(0, 1, 0, 1);
	else
		portrait:SetTexCoord(.01, .99, .01, .99);
	end

	if currentTime - self.lastClickTime > self.timeFrame then
		self:ResetClicks();
	end

	self.clickCount = self.clickCount + 1;
	self.lastClickTime = currentTime;

	if self.clickCount >= self.clickThreshold then
		self:ResetClicks();
		self:Mrow();
	end
end

function MeowFrameMixin:ResetClicks()
	self.clickCount = 0;
end

function MeowFrameMixin:Mrow()
	local sound = self.SoundFileList[fastrandom(1, #self.SoundFileList)];
	PlaySoundFile(sound, "SFX");
end

function MeowFrameMixin:ConcatenateNames(texts)
	local newTexts = ""
	for i = 1, 1 do -- increase value with more contributors
		if LK["Contributor_"..i] then
			newTexts = newTexts .. "\n" .. LK["Contributor_"..i]
		end
	end
	newTexts = newTexts .. "\n" .. LK["Contributor_Anonymous"]

	return newTexts
end

LoreKGUI.PortraitContainer.portrait.MeowFrame = CreateFrame("Button", nil, LoreKGUI);
FrameUtil.SpecializeFrameWithMixins(LoreKGUI.PortraitContainer.portrait.MeowFrame, MeowFrameMixin);
LoreKGUI.PortraitContainer.portrait.MeowFrame:SetAllPoints(LoreKGUI.PortraitContainer.portrait);

LoreKGUI.PortraitContainer.portrait.MeowFrame:SetScript("OnEnter", function(self)
	GameTooltip:SetOwner(self, "ANCHOR_BOTTOM");
	GameTooltip:AddLine(LK["Contributors"], 1, 1, 1, 1, true);
	GameTooltip:AddLine(LK["SpecialThanks"], 1, 1, 1, 1, true);
	GameTooltip:AddLine(MeowFrameMixin:ConcatenateNames(), 1, 1, 1, 1, true);
	GameTooltip:AddTexture("Interface\\ICONS\\UI_JailersTower_Defense", {width = 32, height = 32});
	GameTooltip:Show();
end);
LoreKGUI.PortraitContainer.portrait.MeowFrame:SetScript("OnLeave", function()
	GameTooltip:Hide();
end);


-- here, we just pass in the table containing our saved color config
local function ShowColorPicker(configTable)
	local r, g, b, a = configTable.r, configTable.g, configTable.b, configTable.a;

	local function OnColorChanged()
		local newR, newG, newB = ColorPickerFrame:GetColorRGB();
		local newA = ColorPickerFrame:GetColorAlpha();
		configTable.r, configTable.g, configTable.b, configTable.a = newR, newG, newB, newA;
		LoreKGUI.SetColors()
	end

	local function OnCancel()
		configTable.r, configTable.g, configTable.b, configTable.a = r, g, b, a;
		LoreKGUI.SetColors()
	end

	local options = {
		swatchFunc = OnColorChanged,
		opacityFunc = OnColorChanged,
		cancelFunc = OnCancel,
		hasOpacity = a ~= nil,
		opacity = a,
		r = r,
		g = g,
		b = b,
	};

	ColorPickerFrame:SetupColorPickerAndShow(options);
end

local HasLoginForTab = false
-- Function to handle tab clicks
local function Tab_OnClick(self)
	PanelTemplates_SetTab(self:GetParent(), self:GetID());
	for _, content in pairs(LoreKGUI.contents) do
		content:Hide();
	end
	self.content:Show();
	PlaySound(SOUNDKIT.IG_CHARACTER_INFO_TAB, "SFX");
	--LoreKMainframeTab2:SetEnabled(true) -- until the GUI implemented

	if HasLoginForTab then
		if not C_AddOns.IsAddOnLoaded("Lorekeeper_Mail") then
			LoreKMainframeTab2:SetEnabled(false);
			LoreKMainframeTab2.Text:SetTextColor(.5,.5,.5);
		else
			Lorekeeper_API.SetUpMailColorsAndTextures();
		end
		if not C_AddOns.IsAddOnLoaded("Lorekeeper_Items") then
			LoreKMainframeTab3:SetEnabled(false);
			LoreKMainframeTab3.Text:SetTextColor(.5,.5,.5);
		end
		if C_AddOns.IsAddOnLoaded("Lorekeeper_Cinematics") and Lorekeeper_API.SetUpCinematicsColorsAndTextures then
			Lorekeeper_API.SetUpCinematicsColorsAndTextures();
		else
			LoreKMainframeTab4:SetEnabled(false);
			LoreKMainframeTab4.Text:SetTextColor(.5,.5,.5);
		end
	end

end

-- Function to set up tabs and their associated content frames
local function SetTabs(frame, numTabs, ...)
	frame.numTabs = numTabs;
	frame.contents = {};

	local frameName = frame:GetName();
	local contents = {};
	local previousTab = nil;
	local firstTab = nil;

	for i = 1, numTabs do
		local tab = CreateFrame("Button", frameName.."Tab"..i, frame, "PanelTabButtonTemplate");
		tab:SetID(i);
		tab:SetText(select(i, ...));
		tab:SetScript("OnClick", Tab_OnClick);

		tab.content = CreateFrame("Frame", nil, LoreKGUI);
		tab.content:SetPoint("TOPLEFT", LoreKGUI, "TOPLEFT", 0, 0);
		tab.content:SetPoint("BOTTOMRIGHT", LoreKGUI, "BOTTOMRIGHT", 0, 0);
		tab.content:Hide();
		--tab.content.bg = tab.content:CreateTexture(nil, "BACKGROUND"); -- just to visually identify the panels
		--tab.content.bg:SetAllPoints(true);
		--tab.content.bg:SetColorTexture(math.random(), math.random(), math.random(), 0.6);

		table.insert(contents, tab.content);
		table.insert(frame.contents, tab.content);

		-- Sort the tab spacing and placement. The first is set, then the rest SetPoint to the previous
		if i == 1 then
			tab:SetPoint("TOPLEFT", LoreKGUI, "BOTTOMLEFT", 11, 2);
			firstTab = tab -- Store the first tab reference

			LoreKGUI.LibraryPanel = CreateFrame("Frame", nil, tab.content);
			LoreKGUI.LibraryPanel:SetPoint("TOPLEFT", tab.content, "TOPLEFT", 0, 0);
			LoreKGUI.LibraryPanel:SetPoint("BOTTOMRIGHT", tab.content, "BOTTOMRIGHT", 0, 0);
		elseif i == 2 then
			LoreKGUI.MailPanel = CreateFrame("Frame", nil, tab.content);
			LoreKGUI.MailPanel:SetPoint("TOPLEFT", tab.content, "TOPLEFT", 0, 0);
			LoreKGUI.MailPanel:SetPoint("BOTTOMRIGHT", tab.content, "BOTTOMRIGHT", 0, 0);
			
			tab:SetPoint("TOPLEFT", previousTab, "TOPRIGHT", 3, 0);
		elseif i == 3 then
			LoreKGUI.ItemsPanel = CreateFrame("Frame", nil, tab.content);
			LoreKGUI.ItemsPanel:SetPoint("TOPLEFT", tab.content, "TOPLEFT", 0, 0);
			LoreKGUI.ItemsPanel:SetPoint("BOTTOMRIGHT", tab.content, "BOTTOMRIGHT", 0, 0);

			tab:SetPoint("TOPLEFT", previousTab, "TOPRIGHT", 3, 0);
		elseif i == 4 then
			LoreKGUI.CinematicsPanel = CreateFrame("Frame", nil, tab.content);
			LoreKGUI.CinematicsPanel:SetPoint("TOPLEFT", tab.content, "TOPLEFT", 0, 0);
			LoreKGUI.CinematicsPanel:SetPoint("BOTTOMRIGHT", tab.content, "BOTTOMRIGHT", 0, 0);

			tab:SetPoint("TOPLEFT", previousTab, "TOPRIGHT", 3, 0);
		elseif i == 5 then
			LoreKGUI.SettingsPanel = CreateFrame("Frame", nil, tab.content);
			LoreKGUI.SettingsPanel:SetPoint("TOPLEFT", tab.content, "TOPLEFT", 0, 0);
			LoreKGUI.SettingsPanel:SetPoint("BOTTOMRIGHT", tab.content, "BOTTOMRIGHT", 0, 0);

			tab:SetPoint("TOPLEFT", previousTab, "TOPRIGHT", 3, 0);
		else
			tab:SetPoint("TOPLEFT", previousTab, "TOPRIGHT", 3, 0);
		end
		previousTab = tab -- Store the current tab to reference in the next iteration
	end

	if firstTab then
		Tab_OnClick(firstTab);
	end

	return unpack(contents);
end

-- Set up the tabs and content frames
local content1, content2, content3, content4, content5 = SetTabs(LoreKGUI, 5, LK["Library"], LK["Mail"], LK["Items"], LK["Cinematics"], LK["Settings"]);

--LoreKMainframeTab2.Text:SetTextColor(.5,.5,.5)
--LoreKMainframeTab3.Text:SetTextColor(.5,.5,.5)

LoreKMainframeTab2:SetScript("OnEnter", function(self)
	GameTooltip:SetOwner(self, "ANCHOR_TOP");
	if not C_AddOns.IsAddOnLoaded("Lorekeeper_Mail") then
		GameTooltip:AddLine(LK["AddonDisabled"], 1, 0, 0)
	end
	GameTooltip:Show();
end);
LoreKMainframeTab2:SetScript("OnLeave", function()
	GameTooltip:Hide();
end);

LoreKMainframeTab3:SetScript("OnEnter", function(self)
	GameTooltip:SetOwner(self, "ANCHOR_TOP");
	if not C_AddOns.IsAddOnLoaded("Lorekeeper_Items") then
		GameTooltip:AddLine(LK["AddonDisabled"], 1, 0, 0)
	end
	GameTooltip:Show();
end);
LoreKMainframeTab3:SetScript("OnLeave", function()
	GameTooltip:Hide();
end);

LoreKMainframeTab4:SetScript("OnEnter", function(self)
	GameTooltip:SetOwner(self, "ANCHOR_TOP");
	if not C_AddOns.IsAddOnLoaded("Lorekeeper_Cinematics") then
		GameTooltip:AddLine(LK["AddonDisabled"], 1, 0, 0)
	end
	GameTooltip:Show();
end);
LoreKMainframeTab4:SetScript("OnLeave", function()
	GameTooltip:Hide();
end);


StaticPopupDialogs["LOREK_DELETE_ENTRIES"] = {
	text = LK["DeleteAllConfirm"],
	button1 = YES,
	button2 = NO,
	OnAccept = function()
		print("[PH] get wrecked, this function is not yet implemented");
	end,
	timeout = 0,
	whileDead = false,
	hideOnEscape = true,
};

--------------------------------------------------------------------------
--------------------------------------------------------------------------
 -- Library Panel
--------------------------------------------------------------------------
--------------------------------------------------------------------------

-- Left Side
LoreKGUI.ItemDisplayFrame = CreateFrame("Frame", "LoreKDisplayFrame", LoreKGUI.LibraryPanel, "InsetFrameTemplate3");
local ItemDisplayFrame = LoreKGUI.ItemDisplayFrame;
ItemDisplayFrame:SetWidth(210);
ItemDisplayFrame:SetPoint("TOPLEFT", LoreKGUI.LibraryPanel, "TOPLEFT", 0, -65);
ItemDisplayFrame:SetPoint("BOTTOMLEFT", LoreKGUI.LibraryPanel, "BOTTOMLEFT", 0, 30);

LoreKGUI.TextCount = CreateFrame("Frame", "LoreKDisplayFrame", LoreKGUI.LibraryPanel, "InsetFrameTemplate3");
local TextCount = LoreKGUI.TextCount;
TextCount:SetSize(130,20);
TextCount:SetPoint("TOPLEFT", LoreKGUI.LibraryPanel, "TOPLEFT", 70, -35);
TextCount.Label = TextCount:CreateFontString(nil, "OVERLAY");
TextCount.Label:SetFont(STANDARD_TEXT_FONT, 10);
TextCount.Label:SetPoint("LEFT", TextCount, "LEFT", 10, 0);
TextCount.Label:SetJustifyH("LEFT");
TextCount.Label:SetJustifyV("MIDDLE");
TextCount.Label:SetText("|cnNORMAL_FONT_COLOR:"..LK["TotalItemsLabel"].."|r")
TextCount.Count = TextCount:CreateFontString(nil, "OVERLAY");
TextCount.Count:SetFont(STANDARD_TEXT_FONT, 10);
TextCount.Count:SetPoint("RIGHT", TextCount, "RIGHT", -10, 0);
TextCount.Count:SetJustifyH("RIGHT");
TextCount.Count:SetJustifyV("MIDDLE");
function TextCount.UpdateCount(current, unread, unobtainables, newTexts)
	if not current then TextCount:Hide(); return; end
	TextCount.unobtainables = unobtainables or 0
	TextCount.Count:SetText(current);

	TextCount.totalText = current;
	TextCount.unread = unread;
	TextCount.newTexts = newTexts;
end

function TextCount.Reminder()
	if TextCount.remind then
		return;
	end
	Print(string.format(LK["PotentialReminder"], TextCount.newTexts));
	TextCount.remind = true; -- don't warn for the rest of the session
end

TextCount:SetScript("OnEnter", function(self)
	local totalText = TextCount.totalText;
	local uncollectedText = TextCount.unread;
	local unobtainables = TextCount.unobtainables;
	local newTexts = TextCount.newTexts;

	GameTooltip:SetOwner(self, "ANCHOR_TOP");
	if totalText and totalText > 0 then
		GameTooltip:AddLine("|cnNORMAL_FONT_COLOR:"..LK["TotalItemsLabel"] ..":|r ".. totalText, 1, 1, 1);
	end
	if uncollectedText and uncollectedText > 0 then
		GameTooltip:AddLine("|cnNORMAL_FONT_COLOR:"..LK["ItemsUncollected"] ..":|r ".. uncollectedText, 1, 1, 1);
	end
	--if unobtainables > 0 then
		--GameTooltip:AddLine("|cnNORMAL_FONT_COLOR:"..LK["Unobtainable"] ..":|r ".. unobtainables, 1, 1, 1);
	--end
	if newTexts and newTexts > 0 then
		TextCount.Reminder()
		GameTooltip:AddLine("|cnNORMAL_FONT_COLOR:"..LK["NewTexts"] ..":|r ".. newTexts, 1, 1, 1);
	end
	GameTooltip:Show();
end);
TextCount:SetScript("OnLeave", function()
	GameTooltip:Hide();
end);

--------------------------------------------------------------------------

-- Right Side
LoreKGUI.TextDisplayFrame = CreateFrame("Frame", "LoreKTextDisplayFrame", LoreKGUI.LibraryPanel, "InsetFrameTemplate4");
local TextDisplayFrame = LoreKGUI.TextDisplayFrame;
TextDisplayFrame:SetPoint("TOPLEFT", ItemDisplayFrame, "TOPRIGHT", 19, 0);
TextDisplayFrame:SetPoint("BOTTOMRIGHT", LoreKGUI.LibraryPanel, "BOTTOMRIGHT",-20,30);
TextDisplayFrame.bg = TextDisplayFrame:CreateTexture(nil, "BACKGROUND", nil, 0);
TextDisplayFrame.bg:SetPoint("TOPLEFT", TextDisplayFrame, "TOPLEFT", 3, -40);
TextDisplayFrame.bg:SetPoint("BOTTOMRIGHT", TextDisplayFrame, "BOTTOMRIGHT", -4, 5);
TextDisplayFrame.bg:SetAtlas("QuestBG-Parchment");
--TextDisplayFrame.bg:SetColorTexture(0.1, 0.1, 0.1, 0.8);

-- Scroll frame for Text Preview (Right)
TextDisplayFrame.TextScrollFrame = CreateFrame("ScrollFrame", "LoreKTextScrollFrame", TextDisplayFrame, "ScrollFrameTemplate");
local TextScrollFrame = TextDisplayFrame.TextScrollFrame;
TextScrollFrame:SetPoint("TOPLEFT", TextDisplayFrame, "TOPLEFT", 25,-55);
TextScrollFrame:SetPoint("BOTTOMRIGHT", TextDisplayFrame, "BOTTOMRIGHT", -2,3);
moveFrameXY(TextScrollFrame.ScrollBar, "TOPLEFT", "TOPRIGHT", 0, 45);
moveFrameXY(TextScrollFrame.ScrollBar, "BOTTOMLEFT", "BOTTOMRIGHT", 0, -47);

TextDisplayFrame.TextScrollChild = CreateFrame("Frame", "LoreKTextScrollChild", TextScrollFrame);
local TextScrollChild = TextDisplayFrame.TextScrollChild;
TextScrollChild:SetHeight(1);
TextScrollFrame:SetScrollChild(TextScrollChild);

local _origSetText

--horrible thing i had to do to make the text actually resize with the frame
TextScrollFrame:SetScript("OnSizeChanged", function(self, width, height)
	local childWidth = width - 10;
	TextScrollChild:SetWidth(childWidth);
	if TextScrollChild.textHTML then
		TextScrollChild.textHTML:SetWidth(childWidth - 20);
		if TextScrollChild.textHTML._lastText then
			_origSetText(
				TextScrollChild.textHTML,
				TextScrollChild.textHTML._lastText,
				unpack(TextScrollChild.textHTML._lastTextArgs)
			);
		end
	end
end);

--[[-- mess with later, this isn't the proper way to hide scrollbar when nothing can be scrolled
local anchorsWithScrollBar = {
	CreateAnchor("TOPLEFT", 8, -20);
	CreateAnchor("BOTTOMRIGHT", TextDisplayFrame.TextScrollFrame.ScrollBar, -8, 4),
};

local anchorsWithoutScrollBar = {
	anchorsWithScrollBar[1],
	CreateAnchor("BOTTOMRIGHT", -4, 4);
};

ScrollUtil.InitScrollBoxListWithScrollBar(TextScrollFrame, TextScrollFrame.ScrollBar, TextScrollChild)
ScrollUtil.AddManagedScrollBarVisibilityBehavior(TextScrollFrame, TextScrollFrame.ScrollBar, anchorsWithScrollBar, anchorsWithoutScrollBar);
]]

--------------------------------------------------------------------------

TextDisplayFrame.TitleBackdrop = CreateFrame("Frame", nil, TextDisplayFrame);
local TitleBackdrop = TextDisplayFrame.TitleBackdrop;
TitleBackdrop:SetPoint("BOTTOMLEFT", TextScrollFrame, "TOPLEFT", -21.5, 3);
TitleBackdrop:SetPoint("BOTTOMRIGHT", TextScrollFrame, "TOPRIGHT", -1.5, 3);
TitleBackdrop:SetHeight(48);
TitleBackdrop.tex = TitleBackdrop:CreateTexture(nil, "ARTWORK", nil, 1);
TitleBackdrop.tex:SetAllPoints(true);
TitleBackdrop.tex:SetAtlas("StoryHeader-BG");

TextDisplayFrame.DeleteEntry = CreateFrame("Button", nil, TextDisplayFrame);
local DeleteEntry = TextDisplayFrame.DeleteEntry;
DeleteEntry:SetPoint("BOTTOMRIGHT", TextDisplayFrame, "TOPRIGHT", -2, 3);
DeleteEntry:SetSize(25,25);
DeleteEntry:SetNormalAtlas("128-RedButton-Delete");
DeleteEntry:SetPushedAtlas("128-RedButton-Delete-Pressed");
DeleteEntry:SetDisabledAtlas("128-RedButton-Delete-Disabled");
DeleteEntry:SetHighlightAtlas("128-RedButton-Delete-Highlight");
DeleteEntry:SetEnabled(false);
DeleteEntry:SetScript("OnEnter", function(self)
	GameTooltip:SetOwner(self, "ANCHOR_TOP");
	GameTooltip:AddLine(LK["DeleteAll"], 1, 1, 1, true);
	GameTooltip:Show();
end);
DeleteEntry:SetScript("OnLeave", function()
	GameTooltip:Hide();
end);
DeleteEntry:SetScript("OnClick", function()
	StaticPopup_Show("LOREK_DELETE_ENTRIES");
end)
TextDisplayFrame.DeleteEntry:Hide() -- Not Yet Implemented, probably should have a multitude of options for delete all vs. delete copy

TextScrollChild.textTitle = TitleBackdrop:CreateFontString(nil, "OVERLAY");
TextScrollChild.textTitle:SetFontObject("GameFontHighlightLarge"); -- make into option later
TextScrollChild.textTitle:SetPoint("TOPLEFT", TitleBackdrop, "TOPLEFT", 7,-8);
TextScrollChild.textTitle:SetPoint("BOTTOMRIGHT", TitleBackdrop, "BOTTOMRIGHT", -7, 5);
TextScrollChild.textTitle:SetJustifyH("CENTER");
TextScrollChild.textTitle:SetJustifyV("MIDDLE");

-- The Text Body on the right
TextScrollChild.textHTML = CreateFrame("SimpleHTML", nil, TextDisplayFrame.TextScrollChild);
TextScrollChild.textHTML:SetPoint("TOP", TextScrollChild, "TOP", 0, 0);
TextScrollChild.textHTML:SetPoint("BOTTOM", TextScrollChild, "BOTTOM", 0, 0);

--horrible thing i had to do to make the text actually resize with the frame
_origSetText = TextScrollChild.textHTML.SetText;
TextScrollChild.textHTML.SetText = function(self, text, ...)
	self._lastText = text;
	self._lastTextArgs = { ... };
	return _origSetText(self, text, ...);
end;


-- Set the font for different HTML tags
TextScrollChild.textHTML:SetFont("h1", ITEM_TEXT_FONTS["default"]["H1"]:GetFont());
TextScrollChild.textHTML:SetFont("h2", ITEM_TEXT_FONTS["default"]["H2"]:GetFont());
TextScrollChild.textHTML:SetFont("h3", ITEM_TEXT_FONTS["default"]["H3"]:GetFont());
TextScrollChild.textHTML:SetFont("p", ITEM_TEXT_FONTS["default"]["P"]:GetFont());
TextScrollChild.textHTML:SetJustifyH("p","LEFT");

TextDisplayFrame.PrevPageButton = CreateFrame("Button", nil, TextDisplayFrame, "PagingControlsPrevPageButtonTemplate");
TextDisplayFrame.NextPageButton = CreateFrame("Button", nil, TextDisplayFrame, "PagingControlsNextPageButtonTemplate");
TextDisplayFrame.PrevPageButton:SetPoint("TOP", TextDisplayFrame, "BOTTOM", -12,2);
TextDisplayFrame.NextPageButton:SetPoint("TOP", TextDisplayFrame, "BOTTOM", 28,2);
TextDisplayFrame.PageNumber = TextDisplayFrame.PrevPageButton:CreateFontString(nil, "OVERLAY");
TextDisplayFrame.PageNumber:SetFontObject("GameFontHighlightLarge") -- make into option later
TextDisplayFrame.PageNumber:SetPoint("RIGHT", TextDisplayFrame.PrevPageButton, "LEFT", -15, 0);
TextDisplayFrame.PageNumber:SetJustifyH("RIGHT");
TextDisplayFrame.PrevPageButton:Disable();
TextDisplayFrame.NextPageButton:Disable();
TextDisplayFrame.PrevPageButton:Hide();
TextDisplayFrame.NextPageButton:Hide();
TextDisplayFrame.Type_ID = TextDisplayFrame:CreateFontString(nil, "OVERLAY");
TextDisplayFrame.Type_ID:SetFontObject("GameFontHighlightLarge");
TextDisplayFrame.Type_ID:SetPoint("BOTTOMRIGHT", LoreKMainframe, "BOTTOMRIGHT", -15, 5);

--------------------------------------------------------------------------
-- Variant Text Dropdown Soon(tm)

TextDisplayFrame.VariantDropdown = CreateFrame("DropdownButton", nil, TextDisplayFrame, "WowStyle1DropdownTemplate");
local VariantDropdown = TextDisplayFrame.VariantDropdown;
VariantDropdown:SetPoint("TOPRIGHT", TextDisplayFrame, "TOPRIGHT", -82.5, 22.5);
VariantDropdown:SetSize(130, 20);
VariantDropdown:Hide();

function TextDisplayFrame.GetSelectedTextData(itemID)
	local variantKey = TextDisplayFrame.selectedVariant or "base";
	
	if variantKey == "base" then
		if LK["LocalData"] and LK["LocalData"]["text"] and LK["LocalData"]["text"][itemID] then
			return LK["LocalData"]["text"][itemID]["base"];
		end
		return allData[itemID]["base"];
	end

	if variantKey == "saved" then
		if allData[itemID] and allData[itemID]["base"] then
			return allData[itemID]["base"];
		end
	end

	if allData[itemID] and allData[itemID][variantKey] then
		return allData[itemID][variantKey];
	end

	return allData[itemID]["base"];
end

local function VariantDropdownSetup(dropdown, rootDescription)
	local itemID = TextDisplayFrame.currentItemID;
	if not itemID or not allData[itemID] then return end

	local function IsSelected(variantKey)
		return TextDisplayFrame.selectedVariant == variantKey;
	end

	local function SetSelected(variantKey)
		TextDisplayFrame.selectedVariant = variantKey;
		LoreKGUI.UpdateTextDisplay(itemID);
	end

	local hasLocal = LK["LocalData"] and LK["LocalData"]["text"] and LK["LocalData"]["text"][itemID];
	local svData = LoreK_DB["text"] and LoreK_DB["text"][itemID] and LoreK_DB["text"][itemID]["base"];
	local hasSavedText = svData and svData["text"];

	if hasLocal then
		rootDescription:CreateRadio(LK["Base"], IsSelected, SetSelected, "base");
	elseif hasSavedText then
		rootDescription:CreateRadio(LK["Base"], IsSelected, SetSelected, "saved");
	end

	local copies = {};
	for k, v in pairs(allData[itemID]) do
		if string.find(k, "copy_") then
			table.insert(copies, k);
		end
	end
	table.sort(copies);

	for _, key in ipairs(copies) do
		local index = key:match("copy_(%d+)");
		rootDescription:CreateRadio((LK["Variant"]) .. " " .. index, IsSelected, SetSelected, key);
	end
	
	if hasLocal and hasSavedText then
		local svButton = rootDescription:CreateRadio(LK["Saved"] or "Saved", IsSelected, SetSelected, "saved");
		
		svButton:AddInitializer(function(button, description, menu)
			local rightTexture = button:AttachTexture();
			rightTexture:SetAtlas("UI_Editor_Eye_Icon");
			rightTexture:SetSize(16, 16);
			rightTexture:SetPoint("RIGHT");
		end);
	end
end

VariantDropdown:SetupMenu(VariantDropdownSetup);



function LoreKGUI.UpdateTextDisplay(itemID)
	local data = TextDisplayFrame.GetSelectedTextData(itemID);
	if not data then return end
	
	TextDisplayFrame.currentItemID = itemID;
	local maxPages = 1;
	local pageNum = 1;
	local textTable = data["text"] or {};
	
	if #textTable == 0 then
		TextScrollChild.textHTML:SetText("");
		return;
	end

	local pageText = textTable[pageNum];
	local textTitle = data["title"] or "Unknown";
	local singlePage = data["singlePage"];
	local material = data["material"] or "default";
	
	local isHidden = LoreK_DB["settings"]["hideUnread"];
	local hasRead = false;
	
	if allData[itemID]["base"]["hasRead"] then
		hasRead = true;
	end

	if material == "ParchmentLarge" then
		TextScrollChild.textHTML:SetFont("h1", ITEM_TEXT_FONTS["ParchmentLarge"]["H1"]:GetFont());
		TextScrollChild.textHTML:SetFont("h2", ITEM_TEXT_FONTS["ParchmentLarge"]["H2"]:GetFont());
		TextScrollChild.textHTML:SetFont("h3", ITEM_TEXT_FONTS["ParchmentLarge"]["H3"]:GetFont());
		TextScrollChild.textHTML:SetFont("p", ITEM_TEXT_FONTS["ParchmentLarge"]["P"]:GetFont());
		TextScrollChild.textHTML:SetTextColor("h1", 0, 0, 0, 1);
		TextScrollChild.textHTML:SetTextColor("h2", 0, 0, 0, 1);
		TextScrollChild.textHTML:SetTextColor("h3", 0, 0, 0, 1);
		TextScrollChild.textHTML:SetTextColor("p", 0, 0, 0, 1);
		LoreKGUI.SetFontSizeP();
	else
		TextScrollChild.textHTML:SetFont("h1", ITEM_TEXT_FONTS["default"]["H1"]:GetFont());
		TextScrollChild.textHTML:SetFont("h2", ITEM_TEXT_FONTS["default"]["H2"]:GetFont());
		TextScrollChild.textHTML:SetFont("h3", ITEM_TEXT_FONTS["default"]["H3"]:GetFont());
		TextScrollChild.textHTML:SetFont("p", ITEM_TEXT_FONTS["default"]["P"]:GetFont());
		TextScrollChild.textHTML:SetTextColor("h1", 0, 0, 0, 1);
		TextScrollChild.textHTML:SetTextColor("h2", 0, 0, 0, 1);
		TextScrollChild.textHTML:SetTextColor("h3", 0, 0, 0, 1);
		TextScrollChild.textHTML:SetTextColor("p", 0, 0, 0, 1);
		LoreKGUI.SetFontSizeP();
	end

	TextDisplayFrame.PrevPageButton:Hide();
	TextDisplayFrame.NextPageButton:Hide();
	TextDisplayFrame.PrevPageButton:Disable();
	TextDisplayFrame.NextPageButton:Disable();
	TextDisplayFrame.PageNumber:SetText("");

	LoreKGUI.SetColors();

	if not singlePage and #textTable > 1 then
		maxPages = #textTable;
		local pageNumberText = string.format(PAGE_NUMBER_WITH_MAX, pageNum, maxPages);

		TextDisplayFrame.PrevPageButton:Show();
		TextDisplayFrame.NextPageButton:Show();
		TextDisplayFrame.PageNumber:SetText(pageNumberText);
		TextDisplayFrame.NextPageButton:Enable();

		TextDisplayFrame.PrevPageButton:SetScript("OnClick", function()
			if pageNum ~= 1 then
				pageNum = pageNum - 1;
			end
			if pageNum == 1 then
				TextDisplayFrame.PrevPageButton:Disable();
			end
			TextDisplayFrame.NextPageButton:Enable();
			PlaySound(SOUNDKIT.IG_ABILITY_PAGE_TURN, "SFX", false);

			local currentData = TextDisplayFrame.GetSelectedTextData(itemID);
			local txtTable = currentData["text"];
			
			local pageNumberText = string.format(PAGE_NUMBER_WITH_MAX, pageNum, #txtTable);
			local pText = txtTable[pageNum];
			
			local isHTML = string.lower(ReverseNameAndClass(pText)):find("<html>");
			local HTMLbody;
			if isHTML then
				HTMLbody = string.gsub(ReverseNameAndClass(pText),"<BODY>","<BODY>".."<br />");
			end

			TextDisplayFrame.PageNumber:SetText(pageNumberText);
			TextScrollChild.textTitle:SetText(textTitle, 1, 1, 1, 1, true);
			if isHTML then
				TextScrollChild.textHTML:SetText(HTMLbody or ReverseNameAndClass(pText), false);
			else
				TextScrollChild.textHTML:SetText("\n"..ReverseNameAndClass(pText), false);
			end
		end)

		TextDisplayFrame.NextPageButton:SetScript("OnClick", function()
			local currentData = TextDisplayFrame.GetSelectedTextData(itemID);
			local txtTable = currentData["text"];

			if pageNum ~= #txtTable then
				pageNum = pageNum + 1;
			end
			if pageNum == #txtTable then
				TextDisplayFrame.NextPageButton:Disable();
			end
			TextDisplayFrame.PrevPageButton:Enable();
			PlaySound(SOUNDKIT.IG_ABILITY_PAGE_TURN, "SFX", false);

			local pageNumberText = string.format(PAGE_NUMBER_WITH_MAX, pageNum, #txtTable);
			local pText = txtTable[pageNum];

			local isHTML = string.lower(ReverseNameAndClass(pText)):find("<html>");
			local HTMLbody;
			if isHTML then
				HTMLbody = string.gsub(ReverseNameAndClass(pText),"<BODY>","<BODY>".."<br />");
			end

			TextDisplayFrame.PageNumber:SetText(pageNumberText);
			TextScrollChild.textTitle:SetText(textTitle, 1, 1, 1, 1, true);
			if isHTML then
				TextScrollChild.textHTML:SetText(HTMLbody or ReverseNameAndClass(pText), false);
			else
				TextScrollChild.textHTML:SetText("\n"..ReverseNameAndClass(pText), false);
			end
		end)
	end

	if isHidden and not hasRead then
		TextScrollChild.textHTML:Hide();
		TextDisplayFrame.PrevPageButton:Hide();
		TextDisplayFrame.NextPageButton:Hide();
	else
		TextScrollChild.textHTML:Show();
	end

	TextScrollChild.textTitle:SetText(textTitle, 1, 1, 1, 1, true);
	
	if LoreK_DB.settings.debugAdvanced then
		TextDisplayFrame.Type_ID:SetText(itemID, 1, 1, 1, 1, true);
	else
		TextDisplayFrame.Type_ID:SetText("", 1, 1, 1, 1, true);
	end

	local isHTML = string.lower(ReverseNameAndClass(pageText)):find("<html>");
	local HTMLbody;
	if isHTML then
		HTMLbody = string.gsub(ReverseNameAndClass(pageText),"<BODY>","<BODY>".."<br />");
	end
	
	if isHTML then
		TextScrollChild.textHTML:SetText(HTMLbody or ReverseNameAndClass(pageText), false);
	else
		TextScrollChild.textHTML:SetText("\n"..ReverseNameAndClass(pageText), false);
	end

	LoreKGUI.LibraryPanel.CopyTextEditBoxText = textTitle .. "\n\n";
	for k, v in ipairs(textTable) do
		if k ~= #textTable then
			LoreKGUI.LibraryPanel.CopyTextEditBoxText = LoreKGUI.LibraryPanel.CopyTextEditBoxText .. string.format(PAGE_NUMBER_WITH_MAX, k, #textTable) .. "\n\n" .. v .. "\n\n";
		else
			LoreKGUI.LibraryPanel.CopyTextEditBoxText = LoreKGUI.LibraryPanel.CopyTextEditBoxText .. string.format(PAGE_NUMBER_WITH_MAX, k, #textTable) .. "\n\n" .. v;
		end
	end
	LoreKGUI.LibraryPanel.CopyTextEditBox:SetText(LoreKGUI.LibraryPanel.CopyTextEditBoxText);
end

--------------------------------------------------------------------------
function LoreKGUI.SelectAndShowEntry(itemID)
	if not itemID or not allData or not allData[itemID] then return end

	LoreKGUI:Show();
	Tab_OnClick(LoreKMainframeTab1);

	LoreKGUI.SearchBox:SetText("");

	local elementData = ItemDataProvider:FindByPredicate(function(data) -- made the local var earlier for this
		return data.id == itemID;
	end);

	if not elementData then
		LoreKGUI.UpdateTextDisplay(itemID);
		return;
	end

	ItemScrollBox:ScrollToElementData(elementData, ScrollBoxConstants.AlignCenter);

	RunNextFrame(function()
		local frame = ItemScrollBox:FindFrame(elementData);
		if frame then
			LoreKGUI.SelectionBehavior:Select(frame);
		end

		C_VoiceChat.StopSpeakingText();
		if TTSButton then -- it will get angery
			TTSButton.textPlaying = false;
		end
		DeleteEntry:SetEnabled(true);
		TextDisplayFrame.currentItemID = itemID;

		local hasLocal = LK["LocalData"] and LK["LocalData"]["text"] and LK["LocalData"]["text"][itemID];
		local svData = LoreK_DB["text"] and LoreK_DB["text"][itemID] and LoreK_DB["text"][itemID]["base"];
		local hasSavedText = svData and svData["text"];
		local hasCopies = false;

		if allData[itemID] then
			for k in pairs(allData[itemID]) do
				if string.find(k, "copy_") then
					hasCopies = true;
					break;
				end
			end
		end

		if hasSavedText then
			TextDisplayFrame.selectedVariant = "saved";
		else
			TextDisplayFrame.selectedVariant = "base";
		end

		if hasCopies or (hasLocal and hasSavedText) then
			VariantDropdown:Show();
			VariantDropdown:GenerateMenu();
		else
			VariantDropdown:Hide();
		end

		LoreKGUI.UpdateTextDisplay(itemID);
		if TRP3Button then -- also will get angery
			TRP3Button.ToggleTRP3Button();
		end
	end);
end

--------------------------------------------------------------------------
-- Clean Data
function LoreKGUI.CleanItemData(itemID)
	if not itemID then return end;

	LoreK_DB["text"][itemID]["base"]["text"] = nil;
	LoreK_DB["text"][itemID]["base"]["title"] = nil;
	LoreK_DB["text"][itemID]["base"]["singlePage"] = nil;
	LoreK_DB["text"][itemID]["base"]["pageCount"] = nil;
	LoreK_DB["text"][itemID]["base"]["material"] = nil;

	local textTitle = LK["LocalData"]["text"][itemID]["base"]["title"];
	if LoreK_DB.settings.debugAdvanced then
		Print("Detected exact copy between SVs and LocalData, deleting extra SV data: ",textTitle)
	end

end



--------------------------------------------------------------------------
-- Text to Speech Settings


LoreKGUI.LibraryPanel.TTSButton = CreateFrame("Button", nil, LoreKGUI.LibraryPanel);
local TTSButton = LoreKGUI.LibraryPanel.TTSButton;

LoreKGUI.LibraryPanel.backdropInfo = {
	bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
	edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
	tile = true,
	tileEdge = true,
	tileSize = 8,
	edgeSize = 8,
	insets = { left = 1, right = 1, top = 1, bottom = 1 },
};

LoreKGUI.LibraryPanel.TTSSettings = CreateFrame("Frame", nil, TTSButton, "BackdropTemplate");
local TTSSettings = LoreKGUI.LibraryPanel.TTSSettings;
TTSSettings:SetPoint("TOPRIGHT", TTSButton, "BOTTOMRIGHT", 0, 0);
TTSSettings:SetWidth(130*2);
TTSSettings:SetHeight((26*11));
TTSSettings:SetBackdrop(LoreKGUI.LibraryPanel.backdropInfo);
TTSSettings:SetFrameStrata("HIGH");
TTSSettings:Hide();
TTSSettings:SetBackdropColor(0,0,0,1);
TTSSettings.closebutton = CreateFrame("Button", nil, TTSSettings, "UIPanelCloseButton");
TTSSettings.closebutton:SetWidth(24);
TTSSettings.closebutton:SetHeight(24);
TTSSettings.closebutton:SetPoint("TOPRIGHT", TTSSettings, "TOPRIGHT", 1, 1);
TTSSettings.closebutton:SetScript("OnClick", function(self, button)
	TTSSettings:Hide();
end)

local TTSSettingsPlacer = 1

TTSSettings.TitleFrame = TTSSettings:CreateFontString(nil, "OVERLAY", "GameFontNormal");
TTSSettings.TitleFrame:SetFont(STANDARD_TEXT_FONT, 15);
TTSSettings.TitleFrame:ClearAllPoints();
TTSSettings.TitleFrame:SetPoint("TOPLEFT", TTSSettings, "TOPLEFT",10,TTSSettingsPlacer*-10);
TTSSettings.TitleFrame:SetText(LK["TTSConfigTT"]);
TTSSettingsPlacer = TTSSettingsPlacer+1

TTSSettings.TTSVoiceChoice = CreateFrame("DropdownButton", nil, TTSSettings, "WowStyle1DropdownTemplate");
TTSSettings.TTSVoiceChoice:SetDefaultText(LK["TTSVoiceOption"]);
TTSSettings.TTSVoiceChoice:SetPoint("TOPLEFT", TTSSettings, "TOPLEFT", 10, TTSSettingsPlacer*-25);
TTSSettings.TTSVoiceChoice:SetSize(190, 26);
TTSSettings.TTSVoiceChoice:SetupMenu(function(dropdown, rootDescription)
	local optionHeight = 20;
	local maxElements = 8;
	local maxScrollExtent = optionHeight * maxElements;

	local function IsSelected(voiceID)
		if not LoreK_DB or not LoreK_DB["settings"] or not LoreK_DB["settings"]["TTSSettings"] then
			return false;
		end
		return LoreK_DB["settings"]["TTSSettings"]["voiceID"] == voiceID;
	end

	local function SetSelected(voiceID)
		if LoreK_DB and LoreK_DB["settings"] and LoreK_DB["settings"]["TTSSettings"] then
			LoreK_DB["settings"]["TTSSettings"]["voiceID"] = voiceID;
		end
	end

	for k, v in pairs(C_VoiceChat.GetTtsVoices()) do
		rootDescription:CreateRadio(v.name, IsSelected, SetSelected, v.voiceID);
	end
	
	rootDescription:SetScrollMode(maxScrollExtent);
end);
TTSSettings.TTSVoiceChoice:SetScript("OnEnter", function()
	if not LoreK_DB["settings"]["TTSSettings"]["voiceID"] then return end
	local voiceID = LoreK_DB["settings"]["TTSSettings"]["voiceID"];
	local narratorName;
	for k, v in pairs(C_VoiceChat.GetTtsVoices()) do
		if v.voiceID == voiceID then
			narratorName = v.name;
		end
	end
	if not narratorName then return end
	GameTooltip:SetOwner(TTSSettings.PhoneticReplace_Checkbox, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(narratorName, 1, 1, 1, true);
	GameTooltip:SetWidth(20);
	GameTooltip:Show();
end);
TTSSettings.TTSVoiceChoice:SetScript("OnLeave", function()
	GameTooltip:Hide();
end);

TTSSettingsPlacer = TTSSettingsPlacer+1

TTSSettings.QueuePages_Checkbox = CreateFrame("CheckButton", nil, TTSSettings, "UICheckButtonTemplate");
TTSSettings.QueuePages_Checkbox:SetPoint("TOPLEFT", TTSSettings, "TOPLEFT", 10, TTSSettingsPlacer*-25);
TTSSettings.QueuePages_Checkbox:SetScript("OnClick", function(self)
	if self:GetChecked() then
		LoreK_DB["settings"]["TTSSettings"]["queuePages"] = true;
	else
		LoreK_DB["settings"]["TTSSettings"]["queuePages"] = false;
	end
end);
TTSSettings.QueuePages_Checkbox.Text:SetText(LK["TTSQueuePages"])
TTSSettings.QueuePages_Checkbox:SetScript("OnEnter", function()
	GameTooltip:SetOwner(TTSSettings.QueuePages_Checkbox, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(LK["TTSQueuePagesTT"], 1, 1, 1, true);
	GameTooltip:SetWidth(20);
	GameTooltip:Show();
end);
TTSSettings.QueuePages_Checkbox:SetScript("OnLeave", function()
	GameTooltip:Hide();
end);
TTSSettings.QueuePages_Checkbox.Text:SetScript("OnEnter", function()
	GameTooltip:SetOwner(TTSSettings.QueuePages_Checkbox, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(LK["TTSQueuePagesTT"], 1, 1, 1, true);
	GameTooltip:SetWidth(20);
	GameTooltip:Show();
end);
TTSSettings.QueuePages_Checkbox.Text:SetScript("OnLeave", function()
	GameTooltip:Hide();
end);
TTSSettingsPlacer = TTSSettingsPlacer+1

TTSSettings.PhoneticReplace_Checkbox = CreateFrame("CheckButton", nil, TTSSettings, "UICheckButtonTemplate");
TTSSettings.PhoneticReplace_Checkbox:SetPoint("TOPLEFT", TTSSettings, "TOPLEFT", 10, TTSSettingsPlacer*-25);
TTSSettings.PhoneticReplace_Checkbox:SetScript("OnClick", function(self)
	if self:GetChecked() then
		LoreK_DB["settings"]["TTSSettings"]["phonetics"] = true;
	else
		LoreK_DB["settings"]["TTSSettings"]["phonetics"] = false;
	end
end);
TTSSettings.PhoneticReplace_Checkbox.Text:SetText(LK["Settings_Phonetics"])
TTSSettings.PhoneticReplace_Checkbox:SetScript("OnEnter", function()
	GameTooltip:SetOwner(TTSSettings.PhoneticReplace_Checkbox, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(LK["Settings_PhoneticsTT"], 1, 1, 1, true);
	GameTooltip:SetWidth(20);
	GameTooltip:Show();
end);
TTSSettings.PhoneticReplace_Checkbox:SetScript("OnLeave", function()
	GameTooltip:Hide();
end);
TTSSettings.PhoneticReplace_Checkbox.Text:SetScript("OnEnter", function()
	GameTooltip:SetOwner(TTSSettings.PhoneticReplace_Checkbox, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(LK["Settings_PhoneticsTT"], 1, 1, 1, true);
	GameTooltip:SetWidth(20);
	GameTooltip:Show();
end);
TTSSettings.PhoneticReplace_Checkbox.Text:SetScript("OnLeave", function()
	GameTooltip:Hide();
end);
TTSSettingsPlacer = TTSSettingsPlacer+1

do 
	TTSSettings.VolumeSlider = CreateFrame("Slider", nil, TTSSettings, "MinimalSliderWithSteppersTemplate");
	local VolumeSlider = TTSSettings.VolumeSlider
	VolumeSlider:SetPoint("TOPLEFT", TTSSettings, "TOPLEFT", 30, TTSSettingsPlacer*-27);
	VolumeSlider:SetWidth(190)

	local initialValue = 50
	local minValue = 0
	local maxValue = 100
	local steps = 100

	local formatters = {
		[MinimalSliderWithSteppersMixin.Label.Left] = function(value) return minValue end,
		[MinimalSliderWithSteppersMixin.Label.Right] = function(value) return maxValue end,
		[MinimalSliderWithSteppersMixin.Label.Top] = function(value) return LK["TTSVolume"] .. ": " .. VolumeSlider.Slider:GetValue() end,
		--[MinimalSliderWithSteppersMixin.Label.Min] = function(value) return "Minimum" end,
		--[MinimalSliderWithSteppersMixin.Label.Max] = function(value) return "Maximum" end,
	};

	-- Initialize the slider with the values and formatters
	VolumeSlider:Init(initialValue, minValue, maxValue, steps, formatters);

	local function SliderFuncTest()
		LoreK_DB["settings"]["TTSSettings"]["volume"] = VolumeSlider.Slider:GetValue()
	end
	-- Set up a listener for the value changed event
	VolumeSlider:RegisterCallback("OnValueChanged",SliderFuncTest)

	-- Optionally, enable or disable the slider
	VolumeSlider:SetEnabled(true) -- true to enable, false to disable
end
TTSSettingsPlacer = TTSSettingsPlacer+2

do 
	TTSSettings.SpeedSlider = CreateFrame("Slider", nil, TTSSettings, "MinimalSliderWithSteppersTemplate");
	local SpeedSlider = TTSSettings.SpeedSlider
	SpeedSlider:SetPoint("TOPLEFT", TTSSettings, "TOPLEFT", 30, TTSSettingsPlacer*-25);
	SpeedSlider:SetWidth(190)

	local initialValue = 0
	local minValue = -10
	local maxValue = 10
	local steps = 20

	local formatters = {
		[MinimalSliderWithSteppersMixin.Label.Left] = function(value) return minValue end,
		[MinimalSliderWithSteppersMixin.Label.Right] = function(value) return maxValue end,
		[MinimalSliderWithSteppersMixin.Label.Top] = function(value) return LK["TTSSpeed"] .. ": " .. SpeedSlider.Slider:GetValue() end,
		--[MinimalSliderWithSteppersMixin.Label.Min] = function(value) return "Minimum" end,
		--[MinimalSliderWithSteppersMixin.Label.Max] = function(value) return "Maximum" end,
	};

	-- Initialize the slider with the values and formatters
	SpeedSlider:Init(initialValue, minValue, maxValue, steps, formatters);

	local function SliderFuncTest()
		LoreK_DB["settings"]["TTSSettings"]["speed"] = SpeedSlider.Slider:GetValue()
	end
	-- Set up a listener for the value changed event
	SpeedSlider:RegisterCallback("OnValueChanged",SliderFuncTest)

	-- Optionally, enable or disable the slider
	SpeedSlider:SetEnabled(true) -- true to enable, false to disable
end
TTSSettingsPlacer = TTSSettingsPlacer+2

TTSSettings.PlaySample = CreateFrame("Button", nil, TTSSettings, "SharedButtonTemplate");
TTSSettings.PlaySample:SetPoint("TOPLEFT", TTSSettings, "TOPLEFT", 10, TTSSettingsPlacer*-25);
TTSSettings.PlaySample:SetSize(190, 26);
TTSSettings.PlaySample:SetText(TEXT_TO_SPEECH_PLAY_SAMPLE);
TTSSettings.PlaySample:SetScript("OnClick", function()
	local voiceID = LoreK_DB["settings"]["TTSSettings"]["voiceID"] or 0;
	local speed = LoreK_DB["settings"]["TTSSettings"]["speed"] or 0;
	local volume = LoreK_DB["settings"]["TTSSettings"]["volume"] or 50;
	C_VoiceChat.SpeakText(voiceID, TEXT_TO_SPEECH_SAMPLE_TEXT , 1, speed, volume);
end);
TTSSettingsPlacer = TTSSettingsPlacer+1

TTSSettings.Hyperlink = TTSSettings:CreateFontString(nil, "OVERLAY", "GameFontNormal");
TTSSettings.Hyperlink:SetTextColor(1,1,1,1);
TTSSettings.Hyperlink:SetPoint("TOPLEFT", TTSSettings, "TOPLEFT", -5, TTSSettingsPlacer*-25);
TTSSettings.Hyperlink:SetText("|Tinterface\\chatframe\\ui-chaticon-blizz:12:20|t" .. TEXT_TO_SPEECH_MORE_VOICES);
TTSSettings.Hyperlink:SetWidth(TTSSettings:GetWidth()-20)
TTSSettings:SetHyperlinksEnabled(true)
TTSSettings:SetScript("OnHyperlinkClick", function(self, link, text, button)
	SetItemRef(link, text, button, self)
end)
TTSSettingsPlacer = TTSSettingsPlacer+1


--------------------------------------------------------------------------
-- Text to Speech Functions & Button

local function CleanTextForTTS(text)
	-- Remove \n, \r, and other escape sequences
	local cleanedText = text:gsub("[\n\r\\]", ". "):gsub("|n", " ");
	return cleanedText;
end

function LoreKGUI.LibraryPanel.TTSExecute()
	local bingle = LoreKGUI.TextDisplayFrame.TextScrollChild.textHTML:GetTextData();
	local concText = "";
	for k, v in ipairs(bingle) do
		if bingle[k].text then
			concText = concText .. ". " .. bingle[k].text;
			concText = CleanTextForTTS(concText);
		end
	end

	if TTSButton.textQueuePlaying then
		local voiceID = LoreK_DB["settings"]["TTSSettings"]["voiceID"] or 0;
		local speed = LoreK_DB["settings"]["TTSSettings"]["speed"] or 0;
		local volume = LoreK_DB["settings"]["TTSSettings"]["volume"] or 50;
		concText = replaceWithPhonetics(concText);
		C_VoiceChat.SpeakText(voiceID, concText , 1, speed, volume);
		TTSButton.textPlaying = true;
		return;
	end

	if TTSButton.textPlaying then
		C_VoiceChat.StopSpeakingText();
		TTSButton.textPlaying = false;
	else
		local voiceID = LoreK_DB["settings"]["TTSSettings"]["voiceID"] or 0;
		local speed = LoreK_DB["settings"]["TTSSettings"]["speed"] or 0;
		local volume = LoreK_DB["settings"]["TTSSettings"]["volume"] or 50;
		concText = replaceWithPhonetics(concText);
		C_VoiceChat.SpeakText(voiceID, concText , 1, speed, volume);
		TTSButton.textPlaying = true;
	end
end

TTSButton:SetPoint("TOPRIGHT", LoreKGUI.LibraryPanel, "TOPRIGHT", -50, -40);
TTSButton:SetWidth(24);
TTSButton:SetHeight(24);
TTSButton.tex = TTSButton:CreateTexture(nil, "ARTWORK", nil, 1);
TTSButton.tex:SetAllPoints(TTSButton);
TTSButton.tex:SetAtlas("chatframe-button-icon-TTS");
TTSButton.tex:SetTexCoord(-.08, 1.08, -.08, 1.08);
TTSButton:SetNormalAtlas("chatframe-button-up");
TTSButton:SetPushedAtlas("chatframe-button-down");
TTSButton:SetHighlightAtlas("chatframe-button-highlight");

TTSButton:RegisterEvent("VOICE_CHAT_TTS_PLAYBACK_STARTED");
TTSButton:RegisterEvent("VOICE_CHAT_TTS_PLAYBACK_FINISHED");

function TTSButton.OnEvent(self,event)

	if event == "VOICE_CHAT_TTS_PLAYBACK_STARTED" then
		TTSButton.textPlaying = true;
	end

	if event == "VOICE_CHAT_TTS_PLAYBACK_FINISHED" then
		local queuePages = LoreK_DB["settings"]["TTSSettings"]["queuePages"]
		if queuePages and TTSButton.textPlaying then
			if LoreKTextDisplayFrame.NextPageButton:IsEnabled() then
				LoreKTextDisplayFrame.NextPageButton:Click()
				LoreKGUI.LibraryPanel.TTSExecute();
			else
				TTSButton.textQueuePlaying = false;
			end
		end
		TTSButton.textPlaying = false;
	end
end
TTSButton:SetScript("OnEvent", TTSButton.OnEvent);

TTSButton:SetScript("OnClick", function(self, button, down)
	if button == "LeftButton" and down == false then
		local queuePages = LoreK_DB["settings"]["TTSSettings"]["queuePages"]
		if TTSButton.textQueuePlaying then	
			C_VoiceChat.StopSpeakingText();
			TTSButton.textQueuePlaying = false;
			TTSButton.textPlaying = false;
			return;
		end
		if queuePages then
			TTSButton.textQueuePlaying = true;
		end
		LoreKGUI.LibraryPanel.TTSExecute();
	end
	if button == "RightButton" and down == false then
		if TTSSettings:IsShown() then
			TTSSettings:Hide();
		else
			TTSSettings:Show();
		end
	end
end)
TTSButton:SetScript("OnMouseDown", function()
	TTSButton.tex:SetTexCoord(-.08, 1.16, -.16, 1.08);
end)
TTSButton:SetScript("OnMouseUp", function()
	TTSButton.tex:SetTexCoord(-.08, 1.08, -.08, 1.08);
end)
TTSButton:RegisterForClicks("AnyDown", "AnyUp")


TTSButton:SetScript("OnEnter", function()
	GameTooltip:SetOwner(TTSButton, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(LK["TTSLabelTT"]);
	GameTooltip:AddLine(LK["LeftClick"] ..": " .. LK["TTSReadorStopTT"], 1, 1, 1, true);
	GameTooltip:AddLine(LK["RightClick"] ..": " .. LK["TTSConfigTT"], 1, 1, 1, true);
	GameTooltip:SetWidth(20);
	GameTooltip:Show();
end)
TTSButton:SetScript("OnLeave", function()
	GameTooltip:Hide();
end)

LoreKGUI.LibraryPanel.CopyTextButton = CreateFrame("Button", nil, LoreKGUI.LibraryPanel);
local CopyTextButton = LoreKGUI.LibraryPanel.CopyTextButton;
CopyTextButton:SetPoint("TOPRIGHT", LoreKGUI.LibraryPanel, "TOPRIGHT", -25, -40);
CopyTextButton:SetWidth(24);
CopyTextButton:SetHeight(24);
CopyTextButton.tex = CopyTextButton:CreateTexture(nil, "ARTWORK", nil, 1);
CopyTextButton.tex:SetAllPoints(CopyTextButton);
CopyTextButton.tex:SetTexture("Interface\\AddOns\\Lorekeeper\\Assets\\Textures\\CopyTextIcon");
CopyTextButton.tex:SetTexCoord(.08, .92, .08, .92);
CopyTextButton:SetNormalAtlas("chatframe-button-up");
CopyTextButton:SetPushedAtlas("chatframe-button-down");
CopyTextButton:SetHighlightAtlas("chatframe-button-highlight");

CopyTextButton:SetScript("OnClick", function(self, button, down)
	if button == "LeftButton" and down == false then
		if LoreKGUI.LibraryPanel.CopyTextFrame:IsShown() then
			LoreKGUI.LibraryPanel.CopyTextFrame:Hide();
		else
			LoreKGUI.LibraryPanel.CopyTextFrame:Show();
		end
	end
	--if button == "RightButton" and down == false then
		-- nothing set here yet
	--end
end)
CopyTextButton:SetScript("OnMouseDown", function()
	CopyTextButton.tex:SetTexCoord(.08, 1, 0, .92);
end)
CopyTextButton:SetScript("OnMouseUp", function()
	CopyTextButton.tex:SetTexCoord(.08, .92, .08, .92);
end)
CopyTextButton:RegisterForClicks("AnyDown", "AnyUp")

CopyTextButton:SetScript("OnEnter", function()
	GameTooltip:SetOwner(CopyTextButton, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(LK["CopyTitle"]);
	GameTooltip:AddLine(LK["LeftClick"] ..": " .. LK["CopyDescriptTT"], 1, 1, 1, true);
	GameTooltip:SetWidth(20);
	GameTooltip:Show();
end)
CopyTextButton:SetScript("OnLeave", function()
	GameTooltip:Hide();
end)


LoreKGUI.LibraryPanel.TRP3Button = CreateFrame("Button", nil, LoreKGUI.LibraryPanel);
local TRP3Button = LoreKGUI.LibraryPanel.TRP3Button;
TRP3Button:SetPoint("TOPRIGHT", LoreKGUI.LibraryPanel, "TOPRIGHT", -75, -40);
TRP3Button:SetWidth(24);
TRP3Button:SetHeight(24);
TRP3Button.tex = TRP3Button:CreateTexture(nil, "ARTWORK", nil, 1);
TRP3Button.tex:SetAllPoints(TRP3Button);
TRP3Button.tex:SetTexture("Interface\\AddOns\\totalRP3\\Resources\\trp3minimap");
TRP3Button.tex:SetTexCoord(-.08, 1.08, -.08, 1.08);
TRP3Button:SetNormalAtlas("chatframe-button-up");
TRP3Button:SetPushedAtlas("chatframe-button-down");
TRP3Button:SetHighlightAtlas("chatframe-button-highlight");

function TRP3Button.CopyItem()
	local entryID = TRP3Button.entryID
	local iconID = TRP3Button.iconID
	local iconName

	if type(iconID) == "number" then
		local LRPM12 = LibStub:GetLibrary("LibRPMedia-1.2");
		local iconInfo = LRPM12:GetIconInfoByID(iconID);
		iconName = iconInfo and iconInfo.name;
	else
		iconName = "INV_Misc_Book_09";
	end

	if not entryID or not allData[entryID] then return end
	 -- If the text table is empty, exit the function
	if not next(allData[entryID]["base"]["text"]) then
		if LoreK_DB.settings.debugAdvanced then
			Print("Something exploded! The entry had no text data!")
		end
		return;
	end

	local generatedID = TRP3_API.utils.str.id();
	local itemID, data = TRP3_API.extended.tools.createItem(TRP3_API.extended.tools.getDocumentItemData(generatedID), generatedID);

	local name = allData[entryID]["base"]["title"];
	local innerDocName = name .. "_innerDoc";

	data.BA.NA = name;
	data.IN.doc.BA.NA = innerDocName;
	data.BA.IC = iconName
	-- Initialize an empty table for the pages

	data.IN.doc.PA = {};

	-- Iterate over the text entries
	for index, pageText in ipairs(allData[entryID]["base"]["text"]) do
		local purgedText = TRP3HTMLConvert(pageText)
		table.insert(data.IN.doc.PA, { TX = purgedText });
	end

	Print(string.format(LK["TRP3E_Added"],name));

	-- If you wanna automatically add the book to the main bag
	TRP3_API.inventory.addItem(nil, itemID, { count = 1, madeBy = data.BA and data.BA.CR });
end

TRP3Button:SetScript("OnClick", function(self, button, down)
	if button == "LeftButton" and down == false then
		TRP3Button.CopyItem();
	end
	if button == "RightButton" and down == false then

	end
end)
TRP3Button:SetScript("OnMouseDown", function()
	TRP3Button.tex:SetTexCoord(-.08, 1.16, -.16, 1.08);
end)
TRP3Button:SetScript("OnMouseUp", function()
	TRP3Button.tex:SetTexCoord(-.08, 1.08, -.08, 1.08);
end)
TRP3Button:RegisterForClicks("AnyDown", "AnyUp")


TRP3Button:SetScript("OnEnter", function()
	GameTooltip:SetOwner(TRP3Button, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(LK["TRP3E_Title"]);
	GameTooltip:AddLine(LK["TRP3E_TitleTT"], 1, 1, 1, true);
	GameTooltip:SetWidth(20);
	GameTooltip:Show();
end)
TRP3Button:SetScript("OnLeave", function()
	GameTooltip:Hide();
end)

TRP3Button:Hide();

function TRP3Button.ToggleTRP3Button()
	local IsAddonLoaded = C_AddOns.IsAddOnLoaded("TotalRP3") and C_AddOns.IsAddOnLoaded("totalRP3_Extended");

	if IsAddonLoaded then
		TRP3Button:Show();
	else
		TRP3Button:Hide();
	end
end


--------------------------------------------------------------------------
-- scrollBOX rework

-- The 'button' argument is the frame that our data will inhabit in our list
-- The 'data' argument will be the data table mentioned above
local function ItemInitializer(button, data)
	local itemID = data.id;
	local title = data.base.title;
	if not title then
		return
	end
	local GUIDType = select(1, strsplit("-", itemID));
	local entryID = select(2, strsplit("-", itemID));
	local GObjectEntryID;
	local ItemEntryID;
	local icon_Q;
	local GameObjTT = CHANNEL_CATEGORY_WORLD .. " " .. AUCTION_HOUSE_HEADER_ITEM .."\n|cnGREEN_FONT_COLOR:"..ITEM_CAN_BE_READ.."|r";
	if GUIDType == "Item" then
		ItemEntryID = tonumber(entryID);
	else
		icon_Q = "Interface/ICONS/INV_Misc_Book_09";
	end

	local favorite = data.base.isFavorite;

	local isFavorite = LoreK_DB["text"][itemID] and LoreK_DB["text"][itemID]["base"]["isFavorite"];
	local isManuallyHidden = LoreK_DB["text"][itemID] and LoreK_DB["text"][itemID]["base"]["isHidden"];
	if ItemEntryID then
		icon_Q = select(5,C_Item.GetItemInfoInstant(ItemEntryID));
	else
		icon_Q = "Interface/ICONS/INV_Misc_Book_09" or "Interface/AddOns/Lorekeeper/Assets/Textures/TEMP";
	end
	local hasRead = LoreK_DB["text"] and LoreK_DB["text"][itemID] and LoreK_DB["text"][itemID]["base"] and LoreK_DB["text"][itemID]["base"]["hasRead"]
	local hasMapData = allData[itemID] and allData[itemID]["base"] and allData[itemID]["base"]["mapData"]
	local isObtainable = allData[itemID] and allData[itemID]["base"] and allData[itemID]["base"]["isObtainable"]
	--button:SetWidth(168);
	--button:SetPoint(moveFrameXY(22,0));
	button.tex = button.tex or button:CreateTexture(nil, "OVERLAY", nil, 0);
	button.tex:SetPoint("TOPLEFT", button, "TOPLEFT", button:GetHeight()+2,0);
	button.tex:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", 0,0);
	button.tex:SetAtlas("PetList-ButtonBackground");
	button.icon = button.icon or CreateFrame("Frame", nil, button);
	button.icon:SetPoint("TOPRIGHT", button.tex, "TOPLEFT", -1,0);
	button.icon:SetPoint("BOTTOMRIGHT", button.tex, "BOTTOMLEFT", -1,0);
	button.icon:SetWidth(button:GetHeight());
	button.icon.tex = button.icon.tex or button.icon:CreateTexture(nil, "OVERLAY", nil, 0);
	button.icon.tex:SetTexture(icon_Q);
	button.icon.tex:SetAllPoints(button.icon);
	button.icon.unreadIcon = button.icon.unreadIcon or button.icon:CreateTexture(nil, "OVERLAY", nil, 1);
	button.icon.unreadIcon:SetPoint("TOPLEFT", button.icon, "TOPLEFT", -1,0);
	button.icon.unreadIcon:SetPoint("BOTTOMRIGHT", button.icon, "BOTTOMRIGHT", -1,0);
	button.icon.unreadIcon:SetAtlas("UI-LFG-PendingMark"); -- possibly change to "Campaign-QuestLog-LoreBook"
	if hasRead then
		button.icon.unreadIcon:Hide();
		button.icon.tex:SetDesaturated(false);
	else
		button.icon.unreadIcon:Show();
		button.icon.tex:SetDesaturated(true);
	end
	button.icon.favoritesIcon = button.icon.favoritesIcon or button.icon:CreateTexture(nil, "OVERLAY", nil, 2);
	button.icon.favoritesIcon:SetPoint("TOPLEFT", button.icon, "TOPLEFT", -6,2);
	button.icon.favoritesIcon:SetPoint("BOTTOMRIGHT", button.icon, "BOTTOMRIGHT", -21,17);
	button.icon.favoritesIcon:SetAtlas("PetJournal-FavoritesIcon");
	if isFavorite then
		button.icon.favoritesIcon:Show();
	else
		button.icon.favoritesIcon:Hide();
	end
	button.texHL = button.texHL or button:CreateTexture(nil, "OVERLAY", nil, 3);
	button.texHL:SetAllPoints(button.tex);
	button.texHL:SetAtlas("PetList-ButtonHighlight");
	button.texHL:Hide();
	button.texSel = button.texSel or button:CreateTexture(nil, "OVERLAY", nil, 3);
	button.texSel:SetAllPoints(button.tex);
	button.texSel:SetAtlas("PetList-ButtonSelect");
	button.textFont = button.textFont or button:CreateFontString(nil, "OVERLAY");
	button.textFont:SetFontObject("GameTooltipTextSmall");
	button.textFont:SetPoint("TOPLEFT", button.tex, "TOPLEFT", 5,-3);
	button.textFont:SetPoint("BOTTOMRIGHT", button.tex, "BOTTOMRIGHT", -5,2);
	button.textFont:SetJustifyH("LEFT");
	button.textFont:SetJustifyV("TOP");
	button.textFont:SetText(title);
	button.textFont:SetTextColor(1, 1, 1, 1);
	if not LoreK_DB["text"][itemID] or not hasRead then
		button.textFont:SetTextColor(.5, .5, .5, 1);
	end
	button:SetScript("OnEnter", function()
		button.texHL:Show();
	end);
	button:SetScript("OnLeave", function()
		button.texHL:Hide();
	end);
	button.icon:SetScript("OnEnter", function()
		if ItemEntryID then
			GameTooltip:SetOwner(button.icon, "ANCHOR_TOPLEFT");
			GameTooltip:SetItemByID(ItemEntryID);
			GameTooltip:Show();
		end
		if GUIDType == "GameObject" then
			GameTooltip:SetOwner(button.icon, "ANCHOR_TOPLEFT");
			GameTooltip:AddLine(title);
			GameTooltip:AddLine(GameObjTT, 1, 1, 1);
			GameTooltip:Show();
		end
	end);
	button.icon:SetScript("OnLeave", function()
		GameTooltip:Hide();
	end);
	button:SetScript("OnClick", function(self, BINGLEBUTTON, down)
		if BINGLEBUTTON == "RightButton" then
			if down == false then
				MenuUtil.CreateContextMenu(button, function(ownerRegion, rootDescription)
					rootDescription:CreateTitle(title)
					if isFavorite then
						rootDescription:CreateButton(LK["UnsetFavorite"], function()
							LoreK_DB["text"][itemID]["base"]["isFavorite"] = false;
							LoreKMainframe.PopulateList();
							PlaySound(SOUNDKIT.UI_70_ARTIFACT_FORGE_APPEARANCE_LOCKED, "SFX");
						end)
					else
						if allData[itemID] and allData[itemID]["base"] and allData[itemID]["base"]["hasRead"] then
							rootDescription:CreateButton(LK["SetFavorite"], function()
								LoreK_DB["text"][itemID]["base"]["isFavorite"] = true;
								LoreKMainframe.PopulateList();
								PlaySound(SOUNDKIT.UI_70_ARTIFACT_FORGE_APPEARANCE_APPEARANCE_CHANGE, "SFX");
							end)
						else
							local lockedBtn = rootDescription:CreateButton(LOCKED .. " - " .. NOT_COLLECTED);
							lockedBtn:SetEnabled(false);

							lockedBtn:SetTooltip(function(tooltip, elementDescription)
								GameTooltip_SetTitle(tooltip, MenuUtil.GetElementText(elementDescription));
								GameTooltip_AddErrorLine(tooltip, string.format(BARBERSHOP_CUSTOMIZATION_SOURCE_FORMAT, UNKNOWN));
							end);
						end
					end
					if GUIDType == "GameObject" and hasMapData then
						local mapData = CopyTable(allData[itemID]["base"]["mapData"]);
						local variant = 1;
						for k, v in pairs(mapData) do
							if not C_Map.GetMapInfo(k) then return; end
							rootDescription:CreateButton(LK["SetItemTracked"].." "..variant, function()
								WorldMapFrame:Show();
								WorldMapFrame:SetMapID(k);
								C_Map.SetUserWaypoint(UiMapPoint.CreateFromVector2D(k, CreateVector2D(v[1],v[2])));
								C_SuperTrack.SetSuperTrackedUserWaypoint(true);
								PlaySound(170270);
								return;
							end);
							variant = variant + 1;
						end
					end
					if isManuallyHidden then
						rootDescription:CreateDivider();
						rootDescription:CreateButton(LK["Show"], function()
							LoreK_DB["text"][itemID]["base"]["isHidden"] = false;
							LoreKMainframe.PopulateList();
						end);
					else
						if LoreK_DB["text"][itemID] and LoreK_DB["text"][itemID]["base"] then
							rootDescription:CreateDivider();
							rootDescription:CreateButton(LK["Hide"], function()
								LoreK_DB["text"][itemID]["base"]["isHidden"] = true;
								LoreKMainframe.PopulateList();
							end);
						end
					end
					if LoreK_DB.settings.debugAdvanced and hasRead then
						rootDescription:CreateDivider();
						rootDescription:CreateButton(LK["DebugUnlearn"], function()
							LoreK_DB["text"][itemID]["base"]["hasRead"] = false;
							LoreKMainframe.PopulateList();
						end);
					else
						if LoreK_DB.settings.debugAdvanced and not hasRead then
							rootDescription:CreateDivider();
							rootDescription:CreateButton(LK["DebugLearn"], function()
								if LoreK_DB["text"][itemID] and LoreK_DB["text"][itemID]["base"] then
									if not not LoreK_DB["text"][itemID]["base"]["hasRead"] then
										LoreK_DB["text"][itemID]["base"]["hasRead"] = true;
									else
										LoreK_DB["text"][itemID]["base"] = {
											hasRead = true,
										};
									end
								else
									LoreK_DB["text"][itemID] = {
										base = {
											hasRead = true,
										},
									};
								end
								LoreKMainframe.PopulateList();
							end);
						end
					end
				end)
			end
		else
			LoreKGUI.SelectionBehavior:Select(self);

			C_VoiceChat.StopSpeakingText();
			TTSButton.textPlaying = false;

			PlaySound(SOUNDKIT.UI_JOURNEYS_OPEN_LORE_BOOK, "SFX", true);
			DeleteEntry:SetEnabled(true);
			
			TextDisplayFrame.currentItemID = itemID;

			local hasLocal = LK["LocalData"] and LK["LocalData"]["text"] and LK["LocalData"]["text"][itemID];
			local svData = LoreK_DB["text"] and LoreK_DB["text"][itemID] and LoreK_DB["text"][itemID]["base"];
			local hasSavedText = svData and svData["text"];
			local hasCopies = false;

			if LoreK_DB["text"][itemID] then
				for k in pairs(allData[itemID]) do
					if string.find(k, "copy_") then
						hasCopies = true;
						break;
					end
				end
			end

			if hasSavedText then
				TextDisplayFrame.selectedVariant = "saved";
			else
				TextDisplayFrame.selectedVariant = "base";
			end

			if hasCopies or (hasLocal and hasSavedText) then
				VariantDropdown:Show();
				VariantDropdown:GenerateMenu();
			else
				VariantDropdown:Hide();
			end

			LoreKGUI.UpdateTextDisplay(itemID);

			local icon_Q = data.base.icon;
			TRP3Button.entryID = itemID
			if type(icon_Q) == "number" then 
				TRP3Button.iconID = icon_Q
			else
				TRP3Button.iconID = "INV_Misc_Book_09"
			end
			TRP3Button.ToggleTRP3Button();
		end
	end);
	button:RegisterForClicks("AnyUp", "AnyDown");
end

LoreKGUI.ItemScrollBox = CreateFrame("Frame", nil, ItemDisplayFrame, "WowScrollBoxList");
ItemScrollBox = LoreKGUI.ItemScrollBox;
ItemScrollBox:SetPoint("TOPLEFT", ItemDisplayFrame, "TOPLEFT", 2, -25);
ItemScrollBox:SetPoint("BOTTOMRIGHT", ItemDisplayFrame, "BOTTOMRIGHT", -2, 3);

ItemScrollBox.ItemScrollBar = CreateFrame("EventFrame", nil, ItemDisplayFrame, "MinimalScrollBar");
local ItemScrollBar = ItemScrollBox.ItemScrollBar;
ItemScrollBar:SetPoint("TOPLEFT", ItemScrollBox, "TOPRIGHT", 7, 20);
ItemScrollBar:SetPoint("BOTTOMLEFT", ItemScrollBox, "BOTTOMRIGHT", 7, 0);

ItemDataProvider = CreateDataProvider();
local ItemScrollView = CreateScrollBoxListLinearView();

ScrollUtil.InitScrollBoxListWithScrollBar(ItemScrollBox, ItemScrollBar, ItemScrollView);

-- Correctly order the setup: Initializer/Factory first, then DataProvider.
ItemScrollView:SetElementInitializer("Button", ItemInitializer);
ItemScrollView:SetElementExtent(36);
ItemScrollView:SetDataProvider(ItemDataProvider);


function LoreKGUI:OnSelectionChanged(data, isSelected)
	local f = self.ItemScrollBox:FindFrame(data);
	if not f then
		return;
	end

	f.texSel:SetShown(isSelected);
end

function LoreKGUI:OnFrameInitialized(frame, data)
	local isSelected = self.SelectionBehavior:IsElementDataSelected(data);
	frame.texSel:SetShown(isSelected);
end

LoreKGUI.SelectionBehavior = ScrollUtil.AddSelectionBehavior(ItemScrollBox, SelectionBehaviorFlags.Intrusive);
LoreKGUI.SelectionBehavior:RegisterCallback("OnSelectionChanged", LoreKGUI.OnSelectionChanged, LoreKGUI);

ScrollUtil.AddInitializedFrameCallback(ItemScrollBox, LoreKGUI.OnFrameInitialized, LoreKGUI);


--------------------------------------------------------------------------

-- This function will clear the ScrollView and repopulate it with the given search results
local function PopulateNewDataProvider(newData)
	ItemDataProvider = CreateDataProvider(newData);
	ItemScrollView:SetDataProvider(ItemDataProvider);
end

--sort by favorite, then books that have been read, then alphabetize each category by title
function LoreKGUI.sortFunc(a, b)
	--print("a",a.base.title, a.base.isFavorite)
	if (not not a.base.isFavorite) ~= (not not b.base.isFavorite) then
		return a.base.isFavorite;
	elseif (not not a.base.hasRead) ~= (not not b.base.hasRead) then
		return a.base.hasRead;
	elseif a.base.title and b.base.title then
		return strcmputf8i(a.base.title, b.base.title) < 0;
	end
end

function LoreKGUI.PopulateList()
	local countMax = 0;
	local countCurrent = 0;
	local unobtainables = 0;
	local newTexts = 0;
	local unread = 0;
	if not LoreK_DB or not LoreK_DB["text"] then
		return;
	end

	allData = CopyTable(LK["LocalData"]["text"]);
	for id, data in pairs(LoreK_DB["text"]) do
		if allData[id] then
			Mixin(allData[id].base, data.base);
		else
			allData[id] = CopyTable(data);
		end
	end

	local proxy = {};
	for id, data in pairs(allData) do
		data.id = id;
		tinsert(proxy, data);
		if data.base.isObtainable then
			countMax = countMax + 1;
		end

		if data.base.isObtainable == false then
			unobtainables = unobtainables + 1;
		end
		if data.base.hasRead then
			countCurrent = countCurrent + 1;
		end
		if LK["LocalData"]["text"][id] and not data.base.hasRead then
			unread = unread + 1;
		end
		if data.base.hasRead and not LK["LocalData"]["text"][id] then
			newTexts = newTexts + 1;
		end

		-- Try and clean *all* entries, if this lags a lot, i remove.
		if LoreK_DB["text"][id] and LoreK_DB["text"][id]["base"] and LK["LocalData"]["text"][id] and LK["LocalData"]["text"][id]["base"] then
			if LK.tCompareDeez(LoreK_DB["text"][id]["base"], LK["LocalData"]["text"][id]["base"]) then
				LoreKGUI.CleanItemData(id);
			end
		end
	end

	PopulateNewDataProvider(proxy);
	LoreKGUI.OnTextChanged(LoreKGUI.SearchBox);

	TextCount.UpdateCount(countCurrent, unread, unobtainables, newTexts);

	RefreshMapPins();
end

-- Search box
LoreKGUI.SearchBox = CreateFrame("EditBox", "LoreKSearchBox", ItemDisplayFrame, "SearchBoxTemplate");
LoreKGUI.SearchBox:SetSize(105, 20);
LoreKGUI.SearchBox:SetPoint("TOPLEFT", ItemDisplayFrame, "TOPLEFT", 10, -5);
LoreKGUI.SearchBox:SetAutoFocus(false);

local function escapePattern(text)
	-- Escape all special characters in the user's input
	return text:gsub("([%(%)%.%%%+%-%*%?%[%]%^%$])", "%%%1")
end

function LoreKGUI.OnTextChanged(editBox)
	local SVSettings = LoreK_DB["settings"]["searchMenu"]
	local query = editBox:GetText();
	query = escapePattern(query)

	local matches = {};

	for _, element in pairs(allData) do
		local match = false;
		local base = element["base"]
		
		-- Search Text Match
		if base["title"] and string.find(base["title"]:lower(), query:lower()) then
			
			-- Basic State Filters (Hidden, Unobtainable, Class Specific)
			local stateMatch = true
			
			-- Check Hidden
			if base["isHidden"] and not SVSettings.showHidden then stateMatch = false end
			
			-- Check Unobtainable
			if (base["isObtainable"] == false) and not SVSettings.showUnobtainable then stateMatch = false end
			
			-- Check Collection Status
			if base["hasRead"] and not SVSettings.showCollected then stateMatch = false end
			if (not base["hasRead"]) and not SVSettings.showUnread then stateMatch = false end

			-- Check Class Specific
			if base["isClassSpecific"] and not SVSettings.showClassrestricted then stateMatch = false end

			-- Specific Class
			if SVSettings.filterClass and SVSettings.filterClass ~= "ALL" then
				-- If the item's class ID does not strictly match the filter, hide it
				-- This hides other classes AND generic items (where isClassSpecific is false)
				if base["isClassSpecific"] ~= SVSettings.filterClass then
					stateMatch = false
				end
			end

			-- Expansion
			-- If expansion is nil (SavedVariables/Custom), we always show it
			if base["expansion"] then
				local expID = base["expansion"]
				if SVSettings.expansion and SVSettings.expansion[expID] == false then
					stateMatch = false
				end
			end

			-- Map Data
			if SVSettings.onlyMapData and not base["mapData"] then
				stateMatch = false
			end

			if stateMatch then
				match = true
			end
		end

		-- Add to matches only if exactly one filter condition is met
		if match then
			tinsert(matches, element);
		end
	end

	table.sort(matches, LoreKGUI.sortFunc);
	PopulateNewDataProvider(matches);
end


-- Generally safer to use HookScript on EditBoxes inheriting a template as they likely already have OnTextChanged callbacks defined
-- As a side note, it may be worth debouncing this callback if your search method is particularly performance intensive
LoreKGUI.SearchBox:HookScript("OnTextChanged", LoreKGUI.OnTextChanged);

LoreKGUI.FilterDropdown = CreateFrame("DropdownButton", nil, ItemDisplayFrame, "WowStyle1FilterDropdownTemplate");
LoreKGUI.FilterDropdown.Text:SetText(LK["filter"]);
LoreKGUI.FilterDropdown:SetPoint("LEFT", LoreKGUI.SearchBox, "RIGHT", 3, 0);
LoreKGUI.FilterDropdown:SetSize(80, 20);

local function FilterHandler(owner, rootDescription)
	local SVSettings = LoreK_DB["settings"]["searchMenu"]
	--rootDescription:CreateTitle("Filter Options");
	
	rootDescription:CreateTitle(LK["filter"] or "Filters");
	
	rootDescription:CreateCheckbox(LK["Collected"], function() return SVSettings.showCollected; end, function()
		SVSettings.showCollected = not SVSettings.showCollected;
		LoreKGUI.PopulateList();
	end);

	rootDescription:CreateCheckbox(LK["NotCollected"], function() return SVSettings.showUnread; end, function()
		SVSettings.showUnread = not SVSettings.showUnread;
		LoreKGUI.PopulateList();
	end);

	rootDescription:CreateDivider();

	rootDescription:CreateCheckbox(LK["Hidden"], function() return SVSettings.showHidden; end, function()
		SVSettings.showHidden = not SVSettings.showHidden;
		LoreKGUI.PopulateList();
	end);

	rootDescription:CreateCheckbox(LK["Unobtainable"], function() return SVSettings.showUnobtainable; end, function()
		SVSettings.showUnobtainable = not SVSettings.showUnobtainable;
		LoreKGUI.PopulateList();
	end);

	rootDescription:CreateCheckbox(LK["ClassRestricted"], function() return SVSettings.showClassrestricted; end, function()
		SVSettings.showClassrestricted = not SVSettings.showClassrestricted;
		LoreKGUI.PopulateList();
	end);

	rootDescription:CreateDivider();

	rootDescription:CreateCheckbox(LK["HasMapLocation"], function() return SVSettings.onlyMapData; end, function()
		SVSettings.onlyMapData = not SVSettings.onlyMapData;
		LoreKGUI.PopulateList();
	end);

	rootDescription:CreateDivider();

	local classButton = rootDescription:CreateButton(CLASS);
	
	if not SVSettings.filterClass then SVSettings.filterClass = "ALL" end

	local function IsClassSelected(val)
		return SVSettings.filterClass == val;
	end

	local function SetClassFilter(val)
		SVSettings.filterClass = val;
		LoreKGUI.PopulateList();
	end

	classButton:CreateRadio(ALL, IsClassSelected, SetClassFilter, "ALL");
	
	for i = 1, GetNumClasses() do
		local className, classFile, classID = GetClassInfo(i)
		if classFile then
			local text = "|c"..RAID_CLASS_COLORS[classFile].colorStr .. className .. "|r"
			-- Changed last argument from classFile to classID
			classButton:CreateRadio(text, IsClassSelected, SetClassFilter, classID);
		end
	end

	local expButton = rootDescription:CreateButton(EXPANSION_FILTER_TEXT);
	
	if not SVSettings.expansion then SVSettings.expansion = {} end

	for i = 0, LE_EXPANSION_LEVEL_CURRENT do
		if SVSettings.expansion[i] == nil then SVSettings.expansion[i] = true end

		local expName = _G["EXPANSION_NAME"..i] or (EXPANSION_FILTER_TEXT .. " " .. i)
		
		expButton:CreateCheckbox(expName, function()
			return SVSettings.expansion[i];
		end, function()
			SVSettings.expansion[i] = not SVSettings.expansion[i];
			LoreKGUI.PopulateList();
		end);
	end
end

--------------------------------------------------------------------------
--------------------------------------------------------------------------
-- copy frame

LoreKGUI.LibraryPanel.CopyTextFrame = CreateFrame("Frame", nil, LoreKGUI.LibraryPanel, "BackdropTemplate");
local CopyTextFrame = LoreKGUI.LibraryPanel.CopyTextFrame;
CopyTextFrame:SetPoint("TOPLEFT", LoreKGUI.LibraryPanel, "TOPRIGHT", 10, 0);
CopyTextFrame:SetPoint("BOTTOMLEFT", LoreKGUI.LibraryPanel, "BOTTOMRIGHT", 10, 0);
CopyTextFrame:SetWidth(400);
CopyTextFrame: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}
});
CopyTextFrame:SetBackdropColor(0, 0, 0, 1);
CopyTextFrame.closebutton = CreateFrame("Button", nil, CopyTextFrame, "UIPanelCloseButton");
CopyTextFrame.closebutton:SetWidth(24);
CopyTextFrame.closebutton:SetHeight(24);
CopyTextFrame.closebutton:SetPoint("TOPRIGHT", CopyTextFrame, "TOPRIGHT", 1, 1);
CopyTextFrame.closebutton:SetScript("OnClick", function(self, button)
	CopyTextFrame:Hide();
end)

LoreKGUI.LibraryPanel.copyTextScrollFrame = CreateFrame("ScrollFrame", nil, CopyTextFrame, "ScrollFrameTemplate");
local copyTextScrollFrame = LoreKGUI.LibraryPanel.copyTextScrollFrame;
copyTextScrollFrame:SetPoint("TOPLEFT", 10, -10);
copyTextScrollFrame:SetPoint("BOTTOMRIGHT", -7.5, 0);

LoreKGUI.LibraryPanel.CopyTextEditBox = CreateFrame("EditBox", nil, copyTextScrollFrame);
local CopyTextEditBox = LoreKGUI.LibraryPanel.CopyTextEditBox;
CopyTextEditBox:SetMultiLine(true);
CopyTextEditBox:SetSize(360, 280);
CopyTextEditBox:SetAutoFocus(false);
CopyTextEditBox:SetFontObject(GameFontNormal);
CopyTextEditBox:SetScript("OnEscapePressed", function(self) self:ClearFocus() end);
LoreKGUI.LibraryPanel.CopyTextEditBoxText = "";
local CopyTextEditBoxText = LoreKGUI.LibraryPanel.CopyTextEditBoxText;
CopyTextEditBox:HighlightText();

CopyTextEditBox:SetScript("OnTextChanged", function(self)
	self:SetText(LoreKGUI.LibraryPanel.CopyTextEditBoxText);
end)
copyTextScrollFrame:SetScrollChild(CopyTextEditBox);
copyTextScrollFrame.ScrollBar:ClearAllPoints();
copyTextScrollFrame.ScrollBar:SetPoint("TOPLEFT", copyTextScrollFrame, "TOPRIGHT", -12, -18);
copyTextScrollFrame.ScrollBar:SetPoint("BOTTOMLEFT", copyTextScrollFrame, "BOTTOMRIGHT", -12, 18);

CopyTextFrame:EnableMouse(true);
CopyTextEditBox:HookScript("OnChar", function(self)
	self:SetText(LoreKGUI.LibraryPanel.CopyTextEditBoxText);
end)
CopyTextFrame:Hide();



--------------------------------------------------------------------------
--------------------------------------------------------------------------
 -- Settings Panel
--------------------------------------------------------------------------
--------------------------------------------------------------------------


LoreKGUI.OptionsDisplayFrame = CreateFrame("Frame", nil, LoreKGUI.SettingsPanel, "InsetFrameTemplate3");
LoreKGUI.OptionsDisplayFrame:SetWidth(210);
LoreKGUI.OptionsDisplayFrame:SetPoint("TOPLEFT", LoreKGUI.SettingsPanel, "TOPLEFT", 0, -65);
LoreKGUI.OptionsDisplayFrame:SetPoint("BOTTOMLEFT", LoreKGUI.SettingsPanel, "BOTTOMLEFT", 0, 30);

local SettingsPanelHeader = LoreKGUI.SettingsPanel:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge");
SettingsPanelHeader:SetPoint("TOPLEFT", LoreKGUI.SettingsPanel, "TOPLEFT", 55, -45);
SettingsPanelHeader:SetText(LK["Settings"]);
 
local SettingsSearchBox = CreateFrame("EditBox", nil, LoreKGUI.SettingsPanel, "SearchBoxTemplate");
SettingsSearchBox:SetPoint("TOPLEFT", LoreKGUI.SettingsPanel, "TOPLEFT", 4, -64);
SettingsSearchBox:SetPoint("TOPRIGHT", LoreKGUI.OptionsDisplayFrame, "TOPRIGHT", -4, -64);
SettingsSearchBox:SetHeight(20);
SettingsSearchBox:SetAutoFocus(false);

LoreKGUI.SettingsDisplayFrame = CreateFrame("Frame", nil, LoreKGUI.SettingsPanel, "InsetFrameTemplate4");
local SettingsDisplayFrame = LoreKGUI.SettingsDisplayFrame;
SettingsDisplayFrame:SetPoint("TOPLEFT", LoreKGUI.OptionsDisplayFrame, "TOPRIGHT", 19, 0);
SettingsDisplayFrame:SetPoint("BOTTOMRIGHT", LoreKGUI.SettingsPanel, "BOTTOMRIGHT", -20, 30);

SettingsDisplayFrame.tex = SettingsDisplayFrame:CreateTexture()
SettingsDisplayFrame.tex:SetPoint("TOPLEFT", SettingsDisplayFrame, "TOPLEFT", 3, -3);
SettingsDisplayFrame.tex:SetPoint("BOTTOMRIGHT", SettingsDisplayFrame, "BOTTOMRIGHT", -3, 3);
SettingsDisplayFrame.tex:SetColorTexture(0, 0, 0, 0.5)

LoreKGUI.SettingsScrollFrame = CreateFrame("ScrollFrame", "LoreKSettingsScrollFrame", LoreKGUI.OptionsDisplayFrame, "ScrollFrameTemplate");
local SettingsScrollFrame = LoreKGUI.SettingsScrollFrame;
SettingsScrollFrame:SetPoint("TOPLEFT", LoreKGUI.OptionsDisplayFrame, "TOPLEFT", 4, -5);
SettingsScrollFrame:SetPoint("BOTTOMRIGHT", LoreKGUI.OptionsDisplayFrame, "BOTTOMRIGHT", 0, 3);

LoreKGUI.SettingsScrollChild = CreateFrame("Frame", nil, SettingsScrollFrame);
local SettingsScrollChild = LoreKGUI.SettingsScrollChild;
SettingsScrollChild:SetSize(SettingsScrollFrame:GetWidth(), 1); -- Height will adjust based on content
SettingsScrollFrame:SetScrollChild(SettingsScrollChild);
SettingsScrollChild:SetPoint("TOP", SettingsScrollFrame, "TOP", 0, 0);

SettingsScrollFrame.ScrollBar:ClearAllPoints();
SettingsScrollFrame.ScrollBar:SetPoint("TOPLEFT", SettingsScrollFrame, "TOPRIGHT", 5, 0);
SettingsScrollFrame.ScrollBar:SetPoint("BOTTOMLEFT", SettingsScrollFrame, "BOTTOMRIGHT", 5, 0);

local settingsPanelXPlacer = -27
local settingsPanelYPlacer = 5

SettingsDisplayFrame.hideUnread_Checkbox = CreateFrame("CheckButton", nil, SettingsScrollChild, "UICheckButtonTemplate");
SettingsDisplayFrame.hideUnread_Checkbox:SetPoint("TOPLEFT", SettingsScrollChild, "TOPLEFT", settingsPanelYPlacer, settingsPanelXPlacer*1);
SettingsDisplayFrame.hideUnread_Checkbox:SetScript("OnClick", function(self)
	if self:GetChecked() then
		LoreK_DB["settings"]["hideUnread"] = true;
		PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON, "SFX");
	else
		LoreK_DB["settings"]["hideUnread"] = false;
		PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF, "SFX");
	end
end);
SettingsDisplayFrame.hideUnread_Checkbox.Text:SetText(LK["FogOfLore"])
SettingsDisplayFrame.hideUnread_Checkbox.Text:SetScript("OnEnter", function(self)
	GameTooltip:SetOwner(SettingsDisplayFrame.hideUnread_Checkbox, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(LK["FogOfLoreTT"], 1, 1, 1, true);
	GameTooltip:Show();
end);
SettingsDisplayFrame.hideUnread_Checkbox.Text:SetScript("OnLeave", function(self)
	GameTooltip:Hide();
end);
SettingsDisplayFrame.hideUnread_Checkbox:SetScript("OnEnter", function(self)
	GameTooltip:SetOwner(SettingsDisplayFrame.hideUnread_Checkbox, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(LK["FogOfLoreTT"], 1, 1, 1, true);
	GameTooltip:Show();
end);
SettingsDisplayFrame.hideUnread_Checkbox:SetScript("OnLeave", function(self)
	GameTooltip:Hide();
end);

SettingsDisplayFrame.slashRead_Checkbox = CreateFrame("CheckButton", nil, SettingsScrollChild, "UICheckButtonTemplate");
SettingsDisplayFrame.slashRead_Checkbox:SetPoint("TOPLEFT", SettingsScrollChild, "TOPLEFT", settingsPanelYPlacer, settingsPanelXPlacer*2);
SettingsDisplayFrame.slashRead_Checkbox:SetScript("OnClick", function(self)
	if self:GetChecked() then
		LoreK_DB["settings"]["slashRead"] = true;
		PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON, "SFX");
	else
		LoreK_DB["settings"]["slashRead"] = false;
		PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF, "SFX");
	end
end);
SettingsDisplayFrame.slashRead_Checkbox.Text:SetText(LK["SlashRead"])
SettingsDisplayFrame.slashRead_Checkbox.Text:SetScript("OnEnter", function(self)
	GameTooltip:SetOwner(SettingsDisplayFrame.slashRead_Checkbox, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(LK["SlashReadTT"], 1, 1, 1, true);
	GameTooltip:Show();
end);
SettingsDisplayFrame.slashRead_Checkbox.Text:SetScript("OnLeave", function(self)
	GameTooltip:Hide();
end);
SettingsDisplayFrame.slashRead_Checkbox:SetScript("OnEnter", function(self)
	GameTooltip:SetOwner(SettingsDisplayFrame.slashRead_Checkbox, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(LK["SlashReadTT"], 1, 1, 1, true);
	GameTooltip:Show();
end);
SettingsDisplayFrame.slashRead_Checkbox:SetScript("OnLeave", function(self)
	GameTooltip:Hide();
end);

SettingsDisplayFrame.overrideMats_Checkbox = CreateFrame("CheckButton", nil, SettingsScrollChild, "UICheckButtonTemplate");
SettingsDisplayFrame.overrideMats_Checkbox:SetPoint("TOPLEFT", SettingsScrollChild, "TOPLEFT", settingsPanelYPlacer, settingsPanelXPlacer*3);
SettingsDisplayFrame.overrideMats_Checkbox:SetScript("OnClick", function(self)
	if self:GetChecked() then
		LoreK_DB["settings"]["overrideMaterials"] = true;
		PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON, "SFX");
	else
		LoreK_DB["settings"]["overrideMaterials"] = false;
		PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF, "SFX");
	end
	LoreKGUI.SetParchmentTexture()
end);
SettingsDisplayFrame.overrideMats_Checkbox.Text:SetText(LK["ReplaceMats"])
SettingsDisplayFrame.overrideMats_Checkbox.Text:SetScript("OnEnter", function(self)
	GameTooltip:SetOwner(SettingsDisplayFrame.overrideMats_Checkbox, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(LK["ReplaceMatsTT"], 1, 1, 1, true);
	GameTooltip:Show();
end);
SettingsDisplayFrame.overrideMats_Checkbox.Text:SetScript("OnLeave", function(self)
	GameTooltip:Hide();
end);
SettingsDisplayFrame.overrideMats_Checkbox:SetScript("OnEnter", function(self)
	GameTooltip:SetOwner(SettingsDisplayFrame.overrideMats_Checkbox, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(LK["ReplaceMatsTT"], 1, 1, 1, true);
	GameTooltip:Show();
end);
SettingsDisplayFrame.overrideMats_Checkbox:SetScript("OnLeave", function(self)
	GameTooltip:Hide();
end);

SettingsDisplayFrame.ParchmentTypes = {
	["questBG"] = {
		"QuestBG-Parchment",
		"QuestBG-Parchment-Accessibility",
		"QuestBG-Parchment-Accessibility2",
		"QuestBG-Parchment-Accessibility3",
		"QuestBG-Parchment-Accessibility4",
	},
	["questZone"] = {
		"QuestBG-1027",
		"QuestBG-Azurespan",
		"QuestBG-Dracthyrawaken",
		"QuestBG-Dragonflight",
		"QuestBG-EmeraldDream",
		"QuestBG-Ohnplains",
		"QuestBG-Thaldraszus",
		"QuestBG-Walkingshore",
		"QuestBG-ZaralekCavern",
		"QuestBG-ExilesReach",
		"QuestBG-Alliance",
		"QuestBG-Horde",
		"QuestBG-Legionfall",
		"QuestBG-TheHandofFate",
		"QuestBG-Pandaria",
		"QuestBG-Shadowlands",
		"QuestBG-Ardenweald",
		"QuestBG-Bastion",
		"QuestBG-Kyrian",
		"QuestBG-Necrolord",
		"QuestBG-Fey",
		"QuestBG-Venthyr",
		"QuestBG-Maldraxxus",
		"QuestBG-Oribos",
		"QuestBG-Revendreth",
		"QuestBG-secretsofthefirstones",
		"QuestBG-Candle",
		"QuestBG-Flame",
		"QuestBG-Storm",
		"QuestBG-Web",
		"QuestBG-Trading-Post",
	},
	["professionBG"] = {
		"QuestBG-alchemy",
		"QuestBG-blacksmithing",
		"QuestBG-cooking",
		"QuestBG-enchanting",
		"QuestBG-engineering",
		"QuestBG-fishing",
		"QuestBG-herbalism",
		"QuestBG-inscription",
		"QuestBG-jewelcrafting",
		"QuestBG-leatherworking",
		"QuestBG-mining",
		"QuestBG-skinning",
		"QuestBG-tailoring",
	},
	["misc"] = {
		"spellbook-background-evergreen-right",
		"spellbook-background-evergreen-left",
		"newplayerchat-signup-background",
		"warboard-parchment",
		"ChromieTime-Parchment",
		"QuestLog-empty-quest-background",
		"QuestLog-main-background",
		"Campaign-QuestLog-LoreBackground",
		"GarrLanding-FollowerFrame",
		"UI-Frame-Alliance-CardParchmentWider",
		"UI-Frame-Horde-CardParchmentWider",
		"UI-Frame-Neutral-CardParchmentWider",
		"UI-Frame-Dragonflight-CardParchmentWider",
		"UI-Frame-Kyrian-CardParchmentWider",
		"UI-Frame-Necrolord-CardParchmentWider",
		"UI-Frame-NightFae-CardParchmentWider",
		"UI-Frame-Venthyr-CardParchmentWider",
		"UI-Frame-Marine-CardParchmentWider",
		"UI-Frame-Mechagon-CardParchmentWider",
		"ui-frame-thewarwithin-cardparchmentwider",
		"shop-card-full-15thAnniversary",
		"shop-card-bundle",
		"store-card-splash1-nobanner",
		"store-card-transmog",

	},

};

SettingsDisplayFrame.ParchmentPreview = CreateFrame("Frame", nil, SettingsDisplayFrame);
SettingsDisplayFrame.ParchmentPreview:SetPoint("TOPLEFT", SettingsDisplayFrame, "TOPLEFT", 3, -3);
SettingsDisplayFrame.ParchmentPreview:SetPoint("BOTTOMRIGHT", SettingsDisplayFrame, "BOTTOMRIGHT", -3, 3);
SettingsDisplayFrame.ParchmentPreview.tex = SettingsDisplayFrame.ParchmentPreview:CreateTexture(nil, "OVERLAY", nil, 1);
SettingsDisplayFrame.ParchmentPreview.tex:SetAllPoints(true);

SettingsDisplayFrame.TitlePreview = CreateFrame("Frame", nil, SettingsDisplayFrame.ParchmentPreview);
SettingsDisplayFrame.TitlePreview:SetPoint("TOPLEFT", SettingsDisplayFrame.ParchmentPreview, "TOPLEFT", 1, -1);
SettingsDisplayFrame.TitlePreview:SetPoint("TOPRIGHT", SettingsDisplayFrame.ParchmentPreview, "TOPRIGHT", -1, -1);
SettingsDisplayFrame.TitlePreview:SetHeight(48);
SettingsDisplayFrame.TitlePreview.tex = SettingsDisplayFrame.TitlePreview:CreateTexture(nil, "OVERLAY", nil, 2)
SettingsDisplayFrame.TitlePreview.tex:SetAllPoints(true)
SettingsDisplayFrame.TitlePreview.tex:SetAtlas("StoryHeader-BG")

SettingsDisplayFrame.textTitlePreview = SettingsDisplayFrame.TitlePreview:CreateFontString(nil, "OVERLAY");
SettingsDisplayFrame.textTitlePreview:SetFontObject("GameFontHighlightLarge"); -- make into option later
SettingsDisplayFrame.textTitlePreview:SetPoint("TOPLEFT", SettingsDisplayFrame.TitlePreview, "TOPLEFT", 7,-8);
SettingsDisplayFrame.textTitlePreview:SetPoint("BOTTOMRIGHT", SettingsDisplayFrame.TitlePreview, "BOTTOMRIGHT", -7, 5);
SettingsDisplayFrame.textTitlePreview:SetJustifyH("CENTER");
SettingsDisplayFrame.textTitlePreview:SetJustifyV("MIDDLE");
SettingsDisplayFrame.textTitlePreview:SetText(LK["SampleTitle"])



SettingsDisplayFrame.ParchmentDropdown = CreateFrame("DropdownButton", nil, SettingsScrollChild, "WowStyle1DropdownTemplate");
SettingsDisplayFrame.ParchmentDropdown:SetDefaultText(LK["Textures"]);
SettingsDisplayFrame.ParchmentDropdown:SetPoint("TOPLEFT", SettingsScrollChild, "TOPLEFT", settingsPanelYPlacer, settingsPanelXPlacer*4);
SettingsDisplayFrame.ParchmentDropdown:SetSize(190, 26);
SettingsDisplayFrame.ParchmentDropdown:SetupMenu(function(dropdown, rootDescription)
	local optionHeight = 20;
	local maxElements = 8;
	local maxScrollExtent = optionHeight * maxElements;

	local function IsSelected(material)
		if not LoreK_DB or not LoreK_DB["settings"] then
			return false;
		end
		return LoreK_DB["settings"]["material"] == material;
	end

	local function SetSelected(material)
		if LoreK_DB and LoreK_DB["settings"] then
			LoreK_DB["settings"]["material"] = material;
			LoreKGUI.SetParchmentTexture();
		end
	end

	local questMenu = rootDescription:CreateButton(LK["Quests"]);
	for k, v in ipairs(SettingsDisplayFrame.ParchmentTypes["questBG"]) do
		questMenu:CreateRadio(v, IsSelected, SetSelected, v);
	end
	questMenu:SetScrollMode(maxScrollExtent);

	local campaignMenu = rootDescription:CreateButton(LK["Campaign"]);
	for k, v in ipairs(SettingsDisplayFrame.ParchmentTypes["questZone"]) do
		campaignMenu:CreateRadio(v, IsSelected, SetSelected, v);
	end
	campaignMenu:SetScrollMode(maxScrollExtent);

	local profMenu = rootDescription:CreateButton(LK["Professions"]);
	for k, v in ipairs(SettingsDisplayFrame.ParchmentTypes["professionBG"]) do
		profMenu:CreateRadio(v, IsSelected, SetSelected, v);
	end
	profMenu:SetScrollMode(maxScrollExtent);

	local miscMenu = rootDescription:CreateButton(LK["Misc"]);
	for k, v in ipairs(SettingsDisplayFrame.ParchmentTypes["misc"]) do
		miscMenu:CreateRadio(v, IsSelected, SetSelected, v);
	end
	miscMenu:SetScrollMode(maxScrollExtent);
end)
SettingsDisplayFrame.ParchmentDropdown:SetEnabled(false);

--SettingsDisplayFrame.textHTML = CreateFrame("SimpleHTML", nil, SettingsDisplayFrame.ParchmentPreview);
--SettingsDisplayFrame.textHTML:SetPoint("TOPLEFT", SettingsDisplayFrame.ParchmentPreview, "TOPLEFT", 25, -90);
--SettingsDisplayFrame.textHTML:SetPoint("BOTTOMRIGHT", SettingsDisplayFrame.ParchmentPreview, "BOTTOMRIGHT", -25, 10);
--
--SettingsDisplayFrame.textHTML:SetFont("h1", ITEM_TEXT_FONTS["default"]["H1"]:GetFont());
--SettingsDisplayFrame.textHTML:SetFont("h2", ITEM_TEXT_FONTS["default"]["H2"]:GetFont());
--SettingsDisplayFrame.textHTML:SetFont("h3", ITEM_TEXT_FONTS["default"]["H3"]:GetFont());
--SettingsDisplayFrame.textHTML:SetFont("p", ITEM_TEXT_FONTS["default"]["P"]:GetFont());
--SettingsDisplayFrame.textHTML:SetJustifyH("h1","CENTER");
--SettingsDisplayFrame.textHTML:SetJustifyH("h2","RIGHT");
--SettingsDisplayFrame.textHTML:SetText(LK["SampleText"])

SettingsDisplayFrame.textHTMLLarge = CreateFrame("SimpleHTML", nil, SettingsDisplayFrame.ParchmentPreview);
SettingsDisplayFrame.textHTMLLarge:SetPoint("TOPLEFT", SettingsDisplayFrame.ParchmentPreview, "TOPLEFT", 25, -55);
SettingsDisplayFrame.textHTMLLarge:SetPoint("BOTTOMRIGHT", SettingsDisplayFrame.ParchmentPreview, "BOTTOMRIGHT", -25, 10);

SettingsDisplayFrame.textHTMLLarge:SetFont("h1", ITEM_TEXT_FONTS["ParchmentLarge"]["H1"]:GetFont());
SettingsDisplayFrame.textHTMLLarge:SetFont("h2", ITEM_TEXT_FONTS["ParchmentLarge"]["H2"]:GetFont());
SettingsDisplayFrame.textHTMLLarge:SetFont("h3", ITEM_TEXT_FONTS["ParchmentLarge"]["H3"]:GetFont());
SettingsDisplayFrame.textHTMLLarge:SetFont("p", ITEM_TEXT_FONTS["ParchmentLarge"]["P"]:GetFont());
SettingsDisplayFrame.textHTMLLarge:SetJustifyH("h1","CENTER");
SettingsDisplayFrame.textHTMLLarge:SetJustifyH("h2","RIGHT");

local _origSetTextLarge = SettingsDisplayFrame.textHTMLLarge.SetText;
SettingsDisplayFrame.textHTMLLarge.SetText = function(self, text, ...)
	self._lastText = text;
	self._lastTextArgs = { ... };
	return _origSetTextLarge(self, text, ...);
end;

SettingsDisplayFrame.ParchmentPreview:SetScript("OnSizeChanged", function(self, width, height)
	local innerWidth = width - 50;
	SettingsDisplayFrame.textHTMLLarge:SetWidth(innerWidth);
	if SettingsDisplayFrame.textHTMLLarge._lastText then
		_origSetTextLarge(
			SettingsDisplayFrame.textHTMLLarge,
			SettingsDisplayFrame.textHTMLLarge._lastText,
			unpack(SettingsDisplayFrame.textHTMLLarge._lastTextArgs)
		);
	end
end);

SettingsDisplayFrame.textHTMLLarge:SetText(LK["SampleText"])


local function CreateColorSwatchRow(parent, labelText, getConfigFunc, defaultColor)
	local container = CreateFrame("Frame", nil, parent);
	container:SetSize(190, 26);

	local swatch = CreateFrame("Button", nil, container, "ColorSwatchTemplate");
	swatch:SetPoint("LEFT", container, "LEFT", 4, 0);
	swatch:RegisterForClicks("AnyUp");

	local label = container:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
	label:SetPoint("LEFT", swatch, "RIGHT", 8, 0);
	label:SetPoint("RIGHT", container, "RIGHT", -2, 0);
	label:SetJustifyH("LEFT");
	label:SetText(labelText);

	local function ApplyColor(t)
		if not t then return; end
		local cfg = getConfigFunc();
		if not cfg then return; end
		cfg.r, cfg.g, cfg.b, cfg.a = t.r, t.g, t.b, (t.a or 1);
		swatch.Color:SetVertexColor(cfg.r, cfg.g, cfg.b, cfg.a);
		LoreKGUI.SetColors();
	end

	container.UpdateSwatchColor = function()
		local cfg = getConfigFunc();
		if cfg then
			swatch.Color:SetVertexColor(cfg.r, cfg.g, cfg.b, (cfg.a or 1));
		end
	end

	swatch:SetScript("OnEnter", function(self)
		GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
		GameTooltip:SetText(labelText, 1, 1, 1);
		GameTooltip:AddLine(LK["LC_OpenColorPicker"], 1, 1, 1);
		GameTooltip:AddLine(LK["RC_OpenDropdown"], 1, 1, 1);
		GameTooltip:Show();
	end);
	swatch:SetScript("OnLeave", GameTooltip_Hide);

	swatch:SetScript("OnClick", function(_, button)
		if button == "RightButton" then
			MenuUtil.CreateContextMenu(swatch, function(owner, rootDescription)
				rootDescription:CreateTitle(LK["ColorOptions"]);

				rootDescription:CreateButton(LK["CopyColor"], function()
					LK.ColorClipboard = CopyTable(getConfigFunc());
				end)

				local pasteBtn = rootDescription:CreateButton(LK["PasteColor"], function()
					if not LK.ColorClipboard then return; end
					ApplyColor(CopyTable(LK.ColorClipboard));
				end)
				if not LK.ColorClipboard then
					pasteBtn:SetEnabled(false);
				end;

				rootDescription:CreateButton(RESET_TO_DEFAULT, function()
					ApplyColor(CopyTable(defaultColor));
				end)
			end)
			return;
		end

		local cfg = getConfigFunc();
		local info = {
			r = cfg.r,
			g = cfg.g,
			b = cfg.b,
			opacity = cfg.a,
			hasOpacity = true,
		};
		info.swatchFunc = function()
			local r, g, b = ColorPickerFrame:GetColorRGB();
			local a = ColorPickerFrame:GetColorAlpha();
			ApplyColor({ r = r, g = g, b = b, a = a });
		end
		info.cancelFunc = function()
			local r, g, b, a = ColorPickerFrame:GetPreviousValues();
			ApplyColor({ r = r, g = g, b = b, a = a });
		end
		ColorPickerFrame:SetupColorPickerAndShow(info);
	end)

	container.swatch = swatch;
	return container;
end;

local COLOR_DEFAULT_WHITE = { r = 1, g = 1, b = 1, a = 1 };
local COLOR_DEFAULT_GOLDEN = { r = .85, g = .70, b = .45, a = 1 };
local COLOR_DEFAULT_DARKBROWN = { r = .18, g = .12, b = .05, a = 1 };

SettingsDisplayFrame.materialColorRow = CreateColorSwatchRow(
	SettingsScrollChild,
	LK["ColorPicker"] .. ": " .. LK["TextMaterial"],
	function() return LoreK_DB["settings"]["colors"]["parchment"] end,
	COLOR_DEFAULT_WHITE
);
SettingsDisplayFrame.materialColorRow:SetPoint("TOPLEFT", SettingsScrollChild, "TOPLEFT", settingsPanelYPlacer, settingsPanelXPlacer * 5);

SettingsDisplayFrame.titleColorRow = CreateColorSwatchRow(
	SettingsScrollChild,
	LK["ColorPicker"] .. ": " .. LK["Title"],
	function() return LoreK_DB["settings"]["colors"]["title"] end,
	COLOR_DEFAULT_WHITE
);
SettingsDisplayFrame.titleColorRow:SetPoint("TOPLEFT", SettingsScrollChild, "TOPLEFT", settingsPanelYPlacer, settingsPanelXPlacer * 6);

SettingsDisplayFrame.titleTextColorRow = CreateColorSwatchRow(
	SettingsScrollChild,
	LK["ColorPicker"] .. ": " .. LK["TitleText"],
	function() return LoreK_DB["settings"]["colors"]["titleText"] end,
	COLOR_DEFAULT_GOLDEN
);
SettingsDisplayFrame.titleTextColorRow:SetPoint("TOPLEFT", SettingsScrollChild, "TOPLEFT", settingsPanelYPlacer, settingsPanelXPlacer * 7);

SettingsDisplayFrame.Head1ColorRow = CreateColorSwatchRow(
	SettingsScrollChild,
	LK["ColorPicker"] .. ": " .. LK["Header1"],
	function() return LoreK_DB["settings"]["colors"]["h1"] end,
	COLOR_DEFAULT_DARKBROWN
);
SettingsDisplayFrame.Head1ColorRow:SetPoint("TOPLEFT", SettingsScrollChild, "TOPLEFT", settingsPanelYPlacer, settingsPanelXPlacer * 8);

SettingsDisplayFrame.Head2ColorRow = CreateColorSwatchRow(
	SettingsScrollChild,
	LK["ColorPicker"] .. ": " .. LK["Header2"],
	function() return LoreK_DB["settings"]["colors"]["h2"] end,
	COLOR_DEFAULT_DARKBROWN
);
SettingsDisplayFrame.Head2ColorRow:SetPoint("TOPLEFT", SettingsScrollChild, "TOPLEFT", settingsPanelYPlacer, settingsPanelXPlacer * 9);

SettingsDisplayFrame.Head3ColorRow = CreateColorSwatchRow(
	SettingsScrollChild,
	LK["ColorPicker"] .. ": " .. LK["Header3"],
	function() return LoreK_DB["settings"]["colors"]["h3"] end,
	COLOR_DEFAULT_DARKBROWN
);
SettingsDisplayFrame.Head3ColorRow:SetPoint("TOPLEFT", SettingsScrollChild, "TOPLEFT", settingsPanelYPlacer, settingsPanelXPlacer * 10);

SettingsDisplayFrame.ParaColorRow = CreateColorSwatchRow(
	SettingsScrollChild,
	LK["ColorPicker"] .. ": " .. LK["Paragraph"],
	function() return LoreK_DB["settings"]["colors"]["p"] end,
	COLOR_DEFAULT_DARKBROWN
);
SettingsDisplayFrame.ParaColorRow:SetPoint("TOPLEFT", SettingsScrollChild, "TOPLEFT", settingsPanelYPlacer, settingsPanelXPlacer * 11);

SettingsDisplayFrame.TextSizeDropdown = CreateFrame("DropdownButton", nil, SettingsScrollChild, "WowStyle1DropdownTemplate");
SettingsDisplayFrame.TextSizeDropdown:SetDefaultText(LK["FontSize"]);
SettingsDisplayFrame.TextSizeDropdown:SetPoint("TOPLEFT", SettingsScrollChild, "TOPLEFT", settingsPanelYPlacer, settingsPanelXPlacer*12);
SettingsDisplayFrame.TextSizeDropdown:SetSize(190, 26);
SettingsDisplayFrame.TextSizeDropdown:SetupMenu(function(dropdown, rootDescription)

	local function IsSelected(size)
		if not LoreK_DB or not LoreK_DB["settings"] or not LoreK_DB["settings"]["fontSizeP"] then
			return false;
		end
		return LoreK_DB["settings"]["fontSizeP"]["height"] == size;
	end

	local function SetSelected(size)
		if LoreK_DB and LoreK_DB["settings"] and LoreK_DB["settings"]["fontSizeP"] then
			LoreK_DB["settings"]["fontSizeP"]["height"] = size;
			LoreKGUI.SetFontSizeP();
		end
	end

	rootDescription:CreateRadio(format(FONT_SIZE_TEMPLATE,"13"), IsSelected, SetSelected, 13);
	rootDescription:CreateRadio(format(FONT_SIZE_TEMPLATE,"16"), IsSelected, SetSelected, 16);
	rootDescription:CreateRadio(format(FONT_SIZE_TEMPLATE,"19"), IsSelected, SetSelected, 19);
	rootDescription:CreateRadio(format(FONT_SIZE_TEMPLATE,"22"), IsSelected, SetSelected, 22);

end);

SettingsDisplayFrame.disableCollectSound_Checkbox = CreateFrame("CheckButton", nil, SettingsScrollChild, "UICheckButtonTemplate");
SettingsDisplayFrame.disableCollectSound_Checkbox:SetPoint("TOPLEFT", SettingsScrollChild, "TOPLEFT", settingsPanelYPlacer, settingsPanelXPlacer*13);
SettingsDisplayFrame.disableCollectSound_Checkbox:SetScript("OnClick", function(self)
	if self:GetChecked() then
		LoreK_DB["settings"]["collectSound"] = true;
		PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON, "SFX");
	else
		LoreK_DB["settings"]["collectSound"] = false;
		PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF, "SFX");
	end
end);
SettingsDisplayFrame.disableCollectSound_Checkbox.Text:SetText(LK["ToggleSoundCollected"])
SettingsDisplayFrame.disableCollectSound_Checkbox.Text:SetScript("OnEnter", function(self)
	GameTooltip:SetOwner(SettingsDisplayFrame.disableCollectSound_Checkbox, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(LK["ToggleSoundCollectedTT"], 1, 1, 1, true);
	GameTooltip:Show();
end);
SettingsDisplayFrame.disableCollectSound_Checkbox.Text:SetScript("OnLeave", function(self)
	GameTooltip:Hide();
end);
SettingsDisplayFrame.disableCollectSound_Checkbox:SetScript("OnEnter", function(self)
	GameTooltip:SetOwner(SettingsDisplayFrame.disableCollectSound_Checkbox, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(LK["ToggleSoundCollectedTT"], 1, 1, 1, true);
	GameTooltip:Show();
end);
SettingsDisplayFrame.disableCollectSound_Checkbox:SetScript("OnLeave", function(self)
	GameTooltip:Hide();
end);

SettingsDisplayFrame.disableHolidays_Checkbox = CreateFrame("CheckButton", nil, SettingsScrollChild, "UICheckButtonTemplate");
SettingsDisplayFrame.disableHolidays_Checkbox:SetPoint("TOPLEFT", SettingsScrollChild, "TOPLEFT", settingsPanelYPlacer, settingsPanelXPlacer*14);
SettingsDisplayFrame.disableHolidays_Checkbox:SetScript("OnClick", function(self)
	if self:GetChecked() then
		LoreK_DB["settings"]["holidayThemes"] = true;
		PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON, "SFX");
	else
		LoreK_DB["settings"]["holidayThemes"] = false;
		PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF, "SFX");
	end
	ToggleHolidays();
end);
SettingsDisplayFrame.disableHolidays_Checkbox.Text:SetText(LK["Settings_disableHolidays"])
SettingsDisplayFrame.disableHolidays_Checkbox.Text:SetScript("OnEnter", function(self)
	GameTooltip:SetOwner(SettingsDisplayFrame.disableHolidays_Checkbox, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(LK["Settings_disableHolidaysTT"], 1, 1, 1, true);
	GameTooltip:Show();
end);
SettingsDisplayFrame.disableHolidays_Checkbox.Text:SetScript("OnLeave", function(self)
	GameTooltip:Hide();
end);
SettingsDisplayFrame.disableHolidays_Checkbox:SetScript("OnEnter", function(self)
	GameTooltip:SetOwner(SettingsDisplayFrame.disableHolidays_Checkbox, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(LK["Settings_disableHolidaysTT"], 1, 1, 1, true);
	GameTooltip:Show();
end);
SettingsDisplayFrame.disableHolidays_Checkbox:SetScript("OnLeave", function(self)
	GameTooltip:Hide();
end);

SettingsDisplayFrame.minimap_Checkbox = CreateFrame("CheckButton", nil, SettingsScrollChild, "UICheckButtonTemplate");
SettingsDisplayFrame.minimap_Checkbox:SetPoint("TOPLEFT", SettingsScrollChild, "TOPLEFT", settingsPanelYPlacer, settingsPanelXPlacer*15);
SettingsDisplayFrame.minimap_Checkbox:SetScript("OnClick", function(self)
	if self:GetChecked() then
		LK.SetMinimapButtonShown(true);
		PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON, "SFX");
	else
		LK.SetMinimapButtonShown(false);
		PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF, "SFX");
	end
end);
SettingsDisplayFrame.minimap_Checkbox.Text:SetText(LK["ToggleMinimapIcon"])
LK.MinimapCheckbox = SettingsDisplayFrame.minimap_Checkbox;

--------------------------------------------------------------------------
--Somewhere way below
SettingsDisplayFrame.debug_Checkbox = CreateFrame("CheckButton", nil, SettingsScrollChild, "UICheckButtonTemplate");
SettingsDisplayFrame.debug_Checkbox:SetPoint("TOPLEFT", SettingsScrollChild, "TOPLEFT", settingsPanelYPlacer, settingsPanelXPlacer*19);
SettingsDisplayFrame.debug_Checkbox:SetScript("OnClick", function(self)
	if self:GetChecked() then
		LoreK_DB["settings"]["debugAdvanced"] = true;
		PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON, "SFX");
	else
		LoreK_DB["settings"]["debugAdvanced"] = false;
		PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF, "SFX");
	end
end);
SettingsDisplayFrame.debug_Checkbox.Text:SetText(LK["Debug"])
SettingsDisplayFrame.debug_Checkbox.Text:SetScript("OnEnter", function(self)
	GameTooltip:SetOwner(SettingsDisplayFrame.debug_Checkbox, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(LK["DebugTT"], 1, 1, 1, true);
	GameTooltip:Show();
end);
SettingsDisplayFrame.debug_Checkbox.Text:SetScript("OnLeave", function(self)
	GameTooltip:Hide();
end);
SettingsDisplayFrame.debug_Checkbox:SetScript("OnEnter", function(self)
	GameTooltip:SetOwner(SettingsDisplayFrame.debug_Checkbox, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(LK["DebugTT"], 1, 1, 1, true);
	GameTooltip:Show();
end);
SettingsDisplayFrame.debug_Checkbox:SetScript("OnLeave", function(self)
	GameTooltip:Hide()
end);

--------------------------------------------------------------------------
-- Map Pin Settings
SettingsDisplayFrame.showCollectedPins_Checkbox = CreateFrame("CheckButton", nil, SettingsScrollChild, "UICheckButtonTemplate");
SettingsDisplayFrame.showCollectedPins_Checkbox:SetPoint("TOPLEFT", SettingsScrollChild, "TOPLEFT", settingsPanelYPlacer, settingsPanelXPlacer*16);
SettingsDisplayFrame.showCollectedPins_Checkbox:SetScript("OnClick", function(self)
	if self:GetChecked() then
		LoreK_DB["settings"]["showCollectedPins"] = true;
		PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON, "SFX");
	else
		LoreK_DB["settings"]["showCollectedPins"] = false;
		PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF, "SFX");
	end
	RefreshMapPins();
end);
SettingsDisplayFrame.showCollectedPins_Checkbox.Text:SetText(LK["MapPins_ShowCollected"] or "Show collected map pins");
SettingsDisplayFrame.showCollectedPins_Checkbox.Text:SetScript("OnEnter", function(self)
	GameTooltip:SetOwner(SettingsDisplayFrame.showCollectedPins_Checkbox, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(LK["MapPins_ShowCollectedTT"], 1, 1, 1, true);
	GameTooltip:Show();
end);
SettingsDisplayFrame.showCollectedPins_Checkbox.Text:SetScript("OnLeave", function(self)
	GameTooltip:Hide();
end);
SettingsDisplayFrame.showCollectedPins_Checkbox:SetScript("OnEnter", function(self)
	GameTooltip:SetOwner(SettingsDisplayFrame.showCollectedPins_Checkbox, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(LK["MapPins_ShowCollectedTT"], 1, 1, 1, true);
	GameTooltip:Show();
end);
SettingsDisplayFrame.showCollectedPins_Checkbox:SetScript("OnLeave", function(self)
	GameTooltip:Hide();
end);

SettingsDisplayFrame.hideAllPins_Checkbox = CreateFrame("CheckButton", nil, SettingsScrollChild, "UICheckButtonTemplate");
SettingsDisplayFrame.hideAllPins_Checkbox:SetPoint("TOPLEFT", SettingsScrollChild, "TOPLEFT", settingsPanelYPlacer, settingsPanelXPlacer*17);
SettingsDisplayFrame.hideAllPins_Checkbox:SetScript("OnClick", function(self)
	if self:GetChecked() then
		LoreK_DB["settings"]["hideAllPins"] = true;
		PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON, "SFX");
	else
		LoreK_DB["settings"]["hideAllPins"] = false;
		PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF, "SFX");
	end
	RefreshMapPins();
end);
SettingsDisplayFrame.hideAllPins_Checkbox.Text:SetText(LK["MapPins_HideAll"]);
SettingsDisplayFrame.hideAllPins_Checkbox.Text:SetScript("OnEnter", function(self)
	GameTooltip:SetOwner(SettingsDisplayFrame.hideAllPins_Checkbox, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(LK["MapPins_HideAllTT"], 1, 1, 1, true);
	GameTooltip:Show();
end);
SettingsDisplayFrame.hideAllPins_Checkbox.Text:SetScript("OnLeave", function(self)
	GameTooltip:Hide();
end);
SettingsDisplayFrame.hideAllPins_Checkbox:SetScript("OnEnter", function(self)
	GameTooltip:SetOwner(SettingsDisplayFrame.hideAllPins_Checkbox, "ANCHOR_TOPLEFT");
	GameTooltip:AddLine(LK["MapPins_HideAllTT"], 1, 1, 1, true);
	GameTooltip:Show();
end);
SettingsDisplayFrame.hideAllPins_Checkbox:SetScript("OnLeave", function(self)
	GameTooltip:Hide();
end);

local settingsRegistry = {
	{
		widget = SettingsDisplayFrame.hideUnread_Checkbox,
		searchText = ((LK["FogOfLore"]) .. " " .. (LK["FogOfLoreTT"])):lower(),
	},
	{
		widget = SettingsDisplayFrame.slashRead_Checkbox,
		searchText = ((LK["SlashRead"]) .. " " .. (LK["SlashReadTT"])):lower(),
	},
	{
		widget = SettingsDisplayFrame.overrideMats_Checkbox,
		searchText = ((LK["ReplaceMats"]) .. " " .. (LK["ReplaceMatsTT"])):lower(),
	},
	{
		widget = SettingsDisplayFrame.ParchmentDropdown,
		searchText = ((LK["ParchmentType"])):lower(),
	},
	{
		widget = SettingsDisplayFrame.materialColorRow,
		searchText = ((LK["ColorPicker"]) .. " " .. (LK["TextMaterial"])):lower(),
	},
	{
		widget = SettingsDisplayFrame.titleColorRow,
		searchText = ((LK["ColorPicker"]) .. " " .. (LK["Title"])):lower(),
	},
	{
		widget = SettingsDisplayFrame.titleTextColorRow,
		searchText = ((LK["ColorPicker"]) .. " " .. (LK["TitleText"])):lower(),
	},
	{
		widget = SettingsDisplayFrame.Head1ColorRow,
		searchText = ((LK["ColorPicker"]) .. " " .. (LK["Header1"])):lower(),
	},
	{
		widget = SettingsDisplayFrame.Head2ColorRow,
		searchText = ((LK["ColorPicker"]) .. " " .. (LK["Header2"])):lower(),
	},
	{
		widget = SettingsDisplayFrame.Head3ColorRow,
		searchText = ((LK["ColorPicker"]) .. " " .. (LK["Header3"])):lower(),
	},
	{
		widget = SettingsDisplayFrame.ParaColorRow,
		searchText = ((LK["ColorPicker"]) .. " " .. (LK["Paragraph"])):lower(),
	},
	{
		widget = SettingsDisplayFrame.TextSizeDropdown,
		searchText = ((LK["FontSize"])):lower(),
	},
	{
		widget = SettingsDisplayFrame.disableCollectSound_Checkbox,
		searchText = ((LK["ToggleSoundCollected"]) .. " " .. (LK["ToggleSoundCollectedTT"])):lower(),
	},
	{
		widget = SettingsDisplayFrame.disableHolidays_Checkbox,
		searchText = ((LK["Settings_disableHolidays"]) .. " " .. (LK["Settings_disableHolidaysTT"])):lower(),
	},
	{
		widget = SettingsDisplayFrame.minimap_Checkbox,
		searchText = ((LK["ToggleMinimapIcon"])):lower(),
	},
	{
		widget = SettingsDisplayFrame.showCollectedPins_Checkbox,
		searchText = ((LK["MapPins_ShowCollected"]) .. " " .. (LK["MapPins_ShowCollectedTT"])):lower(),
	},
	{
		widget = SettingsDisplayFrame.hideAllPins_Checkbox,
		searchText = ((LK["MapPins_HideAll"]) .. " " .. (LK["MapPins_HideAllTT"])):lower(),
	},
	{
		widget = SettingsDisplayFrame.debug_Checkbox,
		searchText = ((LK["Debug"]) .. " " .. (LK["DebugTT"])):lower(),
	},
};

local function LayoutSettings(query)
	local rowHeight = math.abs(settingsPanelXPlacer);
	local xOffset = settingsPanelYPlacer;
	local rowIndex = 0;

	for _, entry in ipairs(settingsRegistry) do
		local matches = (query == "") or (entry.searchText and entry.searchText:find(query, 1, true));
		if matches then
			entry.widget:Show();
			entry.widget:ClearAllPoints();
			entry.widget:SetPoint(
				"TOPLEFT", SettingsScrollChild, "TOPLEFT",
				xOffset, -(rowIndex + 1) * rowHeight
			);
			rowIndex = rowIndex + 1;
		else
			entry.widget:Hide();
		end
	end

	local totalHeight = math.max(1, rowIndex * rowHeight + rowHeight);
	SettingsScrollChild:SetHeight(totalHeight);
end;

SettingsSearchBox:HookScript("OnTextChanged", function(self)
	self._searchTimer = 0;
	self:SetScript("OnUpdate", function(self, elapsed)
		self._searchTimer = self._searchTimer + elapsed;
		if self._searchTimer >= 0.2 then
			self._searchTimer = 0;
			self:SetScript("OnUpdate", nil);
			LayoutSettings(self:GetText():lower());
		end;
	end);
end);

LayoutSettings("");

--------------------------------------------------------------------------
--------------------------------------------------------------------------
 -- Addon Load
--------------------------------------------------------------------------
--------------------------------------------------------------------------

function LoreKGUI.SetParchmentTexture()
	if LoreK_DB["settings"]["overrideMaterials"] and LoreK_DB["settings"]["material"] then
		SettingsDisplayFrame.ParchmentDropdown:SetEnabled(true);
		SettingsDisplayFrame.ParchmentPreview.tex:SetAtlas(LoreK_DB["settings"]["material"]); -- dummy frame
		TextDisplayFrame.bg:SetAtlas(LoreK_DB["settings"]["material"]); -- actual frame
	else
		SettingsDisplayFrame.ParchmentDropdown:SetEnabled(false);
		SettingsDisplayFrame.ParchmentPreview.tex:SetAtlas("QuestBG-Parchment"); -- dummy frame
		TextDisplayFrame.bg:SetAtlas("QuestBG-Parchment"); -- actual frame
	end
	if LoreK_DB["settings"]["overrideMaterials"] then
		SettingsDisplayFrame.ParchmentDropdown:SetEnabled(true);
	end
end

function LoreKGUI.SetColors()
	if not LoreK_DB["settings"]["colors"] then
		LoreK_DB["settings"]["colors"] = {
			["parchment"] = {
				r = 1,
				g = 1,
				b = 1,
				a = 1,
			},
			["title"] = {
				r = 1,
				g = 1,
				b = 1,
				a = 1,
			},
			["titleText"] = {
				r = .85,
				g = .70,
				b = .45,
				a = 1,
			},
			["h1"] = {
				r = .18,
				g = .12,
				b = .05,
				a = 1,
			},
			["h2"] = {
				r = .18,
				g = .12,
				b = .05,
				a = 1,
			},
			["h3"] = {
				r = .18,
				g = .12,
				b = .05,
				a = 1,
			},
			["p"] = {
				r = .18,
				g = .12,
				b = .05,
				a = 1,
			},
		};
	end;

	SettingsDisplayFrame.TitlePreview.tex:SetVertexColor(ColorMixin.GetRGBA(LoreK_DB["settings"]["colors"]["title"])); -- dummy frame
	TitleBackdrop.tex:SetVertexColor(ColorMixin.GetRGBA(LoreK_DB["settings"]["colors"]["title"])); -- actual frame
	SettingsDisplayFrame.ParchmentPreview.tex:SetVertexColor(ColorMixin.GetRGBA(LoreK_DB["settings"]["colors"]["parchment"])); -- dummy frame
	TextDisplayFrame.bg:SetVertexColor(ColorMixin.GetRGBA(LoreK_DB["settings"]["colors"]["parchment"])); -- actual frame

	SettingsDisplayFrame.textTitlePreview:SetTextColor(ColorMixin.GetRGBA(LoreK_DB["settings"]["colors"]["titleText"])); -- dummy text
	TextScrollChild.textTitle:SetTextColor(ColorMixin.GetRGBA(LoreK_DB["settings"]["colors"]["titleText"])); -- actual text
	--SettingsDisplayFrame.textHTML:SetTextColor("h1", ColorMixin.GetRGBA(LoreK_DB["settings"]["colors"]["h1"])); -- dummy text
	--SettingsDisplayFrame.textHTML:SetTextColor("h2", ColorMixin.GetRGBA(LoreK_DB["settings"]["colors"]["h2"]));
	--SettingsDisplayFrame.textHTML:SetTextColor("h3", ColorMixin.GetRGBA(LoreK_DB["settings"]["colors"]["h3"]));
	--SettingsDisplayFrame.textHTML:SetTextColor("p", ColorMixin.GetRGBA(LoreK_DB["settings"]["colors"]["p"]));

	SettingsDisplayFrame.textHTMLLarge:SetTextColor("h1", ColorMixin.GetRGBA(LoreK_DB["settings"]["colors"]["h1"])); -- dummy text
	SettingsDisplayFrame.textHTMLLarge:SetTextColor("h2", ColorMixin.GetRGBA(LoreK_DB["settings"]["colors"]["h2"]));
	SettingsDisplayFrame.textHTMLLarge:SetTextColor("h3", ColorMixin.GetRGBA(LoreK_DB["settings"]["colors"]["h3"]));
	SettingsDisplayFrame.textHTMLLarge:SetTextColor("p", ColorMixin.GetRGBA(LoreK_DB["settings"]["colors"]["p"]));

	TextScrollChild.textHTML:SetTextColor("h1", ColorMixin.GetRGBA(LoreK_DB["settings"]["colors"]["h1"])); --actual text colors
	TextScrollChild.textHTML:SetTextColor("h2", ColorMixin.GetRGBA(LoreK_DB["settings"]["colors"]["h2"]));
	TextScrollChild.textHTML:SetTextColor("h3", ColorMixin.GetRGBA(LoreK_DB["settings"]["colors"]["h3"]));
	TextScrollChild.textHTML:SetTextColor("p", ColorMixin.GetRGBA(LoreK_DB["settings"]["colors"]["p"]));

	if SettingsDisplayFrame.materialColorRow then
		SettingsDisplayFrame.materialColorRow:UpdateSwatchColor();
	end
	if SettingsDisplayFrame.titleColorRow then
		SettingsDisplayFrame.titleColorRow:UpdateSwatchColor();
	end
	if SettingsDisplayFrame.titleTextColorRow then
		SettingsDisplayFrame.titleTextColorRow:UpdateSwatchColor();
	end
	if SettingsDisplayFrame.Head1ColorRow then
		SettingsDisplayFrame.Head1ColorRow:UpdateSwatchColor();
	end
	if SettingsDisplayFrame.Head2ColorRow then
		SettingsDisplayFrame.Head2ColorRow:UpdateSwatchColor();
	end
	if SettingsDisplayFrame.Head3ColorRow then
		SettingsDisplayFrame.Head3ColorRow:UpdateSwatchColor();
	end
	if SettingsDisplayFrame.ParaColorRow then
		SettingsDisplayFrame.ParaColorRow:UpdateSwatchColor();
	end

end;

function LoreKGUI.SetFontSizeP()
	local fontFile, height, flags = ITEM_TEXT_FONTS["ParchmentLarge"]["P"]:GetFont()
	if not LoreK_DB["settings"]["fontSizeP"] then
		LoreK_DB["settings"]["fontSizeP"] = {
			fontFile, height, flags,
		};
	end;

	--SettingsDisplayFrame.textHTML:SetFont("p", fontFile, LoreK_DB["settings"]["fontSizeP"]["height"] or 13, flags); -- dummy text
	SettingsDisplayFrame.textHTMLLarge:SetFont("p", fontFile, LoreK_DB["settings"]["fontSizeP"]["height"] or 13, flags); -- dummy text
	TextScrollChild.textHTML:SetFont("p", fontFile, LoreK_DB["settings"]["fontSizeP"]["height"] or 13, flags);
end;


LoreKGUI.Events = CreateFrame("Frame");
LoreKGUI.Events:RegisterEvent("ADDON_LOADED");
LoreKGUI.Events:RegisterEvent("PLAYER_ENTERING_WORLD");


function LoreKGUI.Initialize(self, event, arg1)
	if event == "ADDON_LOADED" and arg1 == "Lorekeeper" then
		if not LoreK_DB["settings"] then
			LoreK_DB["settings"] = {
				overrideMaterials = false,
				hideUnread = true,
				slashRead = false,
				debugAdvanced = false,
				collectSound = false,
				searchMenu = {
					showUnobtainable = false,
					showClassrestricted = true,
					showHidden = false,
					showCollected = true,
					showUnread = true,
					expansion = {
						classic = true,
						tbc = true,
						wrath = true,
						cata = true,
						mop = true,
						wod = true,
						legion = true,
						bfa = true,
						shadowlands = true,
						dragonflight = true,
						warwithin = true,
						midnight = true,
						lasttitan = true,
					},
				},
			};
		end
		if not LoreK_DB["settings"]["searchMenu"] then
			LoreK_DB["settings"]["searchMenu"] = {
				showUnobtainable = false,
				showClassrestricted = true,
				showHidden = false,
				showCollected = true,
				showUnread = true,
				expansion = {
					classic = true,
					tbc = true,
					wrath = true,
					cata = true,
					mop = true,
					wod = true,
					legion = true,
					bfa = true,
					shadowlands = true,
					dragonflight = true,
					warwithin = true,
					midnight = true,
					lasttitan = true,
				},
			};
		end
		if not LoreK_DB["settings"]["TTSSettings"] then
			LoreK_DB["settings"]["TTSSettings"] = CopyTable(defaultTTSSettings);
		end
		if LoreK_DB["settings"]["TTSSettings"]["phonetics"] == nil then
			LoreK_DB["settings"]["TTSSettings"]["phonetics"] = true;
		end
		if LoreK_DB["settings"]["holidayThemes"] == nil then
			LoreK_DB["settings"]["holidayThemes"] = true;
		end
		if LoreK_DB["settings"]["searchMenu"].onlyMapData == nil then
			 LoreK_DB["settings"]["searchMenu"].onlyMapData = false
		end
		if LoreK_DB["settings"]["searchMenu"].filterClass == nil then
			 LoreK_DB["settings"]["searchMenu"].filterClass = "ALL"
		end
		if not LoreK_DB["settings"]["searchMenu"].expansion then
			 LoreK_DB["settings"]["searchMenu"].expansion = {}
			 for i = 0, LE_EXPANSION_LEVEL_CURRENT do
				 LoreK_DB["settings"]["searchMenu"].expansion[i] = true
			 end
		end
		if LoreK_DB["settings"]["showCollectedPins"] == nil then
			LoreK_DB["settings"]["showCollectedPins"] = false;
		end
		if LoreK_DB["settings"]["hideAllPins"] == nil then
			LoreK_DB["settings"]["hideAllPins"] = false;
		end
		TTSSettings.QueuePages_Checkbox:SetChecked(LoreK_DB["settings"]["TTSSettings"]["queuePages"]);
		TTSSettings.PhoneticReplace_Checkbox:SetChecked(LoreK_DB["settings"]["TTSSettings"]["phonetics"]);
		TTSSettings.VolumeSlider.Slider:SetValue(LoreK_DB["settings"]["TTSSettings"]["volume"]);
		TTSSettings.SpeedSlider.Slider:SetValue(LoreK_DB["settings"]["TTSSettings"]["speed"]);

		LoreKGUI.FilterDropdown:SetupMenu(FilterHandler);

		LoreKGUI.PopulateList();
		SettingsDisplayFrame.overrideMats_Checkbox:SetChecked(LoreK_DB["settings"]["overrideMaterials"]);
		SettingsDisplayFrame.hideUnread_Checkbox:SetChecked(LoreK_DB["settings"]["hideUnread"]);
		SettingsDisplayFrame.slashRead_Checkbox:SetChecked(LoreK_DB["settings"]["slashRead"]);
		SettingsDisplayFrame.disableCollectSound_Checkbox:SetChecked(LoreK_DB["settings"]["collectSound"]);
		SettingsDisplayFrame.disableHolidays_Checkbox:SetChecked(LoreK_DB["settings"]["holidayThemes"]);
		SettingsDisplayFrame.minimap_Checkbox:SetChecked(not LK.AceAddon.db.profile.minimap.hide);
		SettingsDisplayFrame.debug_Checkbox:SetChecked(LoreK_DB["settings"]["debugAdvanced"]);
		SettingsDisplayFrame.showCollectedPins_Checkbox:SetChecked(LoreK_DB["settings"]["showCollectedPins"]);
		SettingsDisplayFrame.hideAllPins_Checkbox:SetChecked(LoreK_DB["settings"]["hideAllPins"]);
		
		LoreKGUI.SetParchmentTexture();
		LoreKGUI.SetColors();
		LoreKGUI.SetFontSizeP();

		HolidaysTheme.Bottom:SetPoint("CENTER", LoreKGUI.TextDisplayFrame, "CENTER", 0, 0);
	end
	if event == "PLAYER_ENTERING_WORLD" then
		HasLoginForTab = true
		if not C_AddOns.IsAddOnLoaded("Lorekeeper_Mail") then
			LoreKMainframeTab2:SetEnabled(false);
			LoreKMainframeTab2.Text:SetTextColor(.5,.5,.5);
		end
		if not C_AddOns.IsAddOnLoaded("Lorekeeper_Items") then
			LoreKMainframeTab3:SetEnabled(false);
			LoreKMainframeTab3.Text:SetTextColor(.5,.5,.5);
		end
		if not C_AddOns.IsAddOnLoaded("Lorekeeper_Cinematics") then
			LoreKMainframeTab4:SetEnabled(false);
			LoreKMainframeTab4.Text:SetTextColor(.5,.5,.5);
		end
	end
end

LoreKGUI.Events:SetScript("OnEvent", LoreKGUI.Initialize);

local function IsBusy()
	if C_InstanceEncounter and C_InstanceEncounter.IsEncounterInProgress and C_InstanceEncounter.IsEncounterInProgress() then
		return true
	end
	
	if UnitAffectingCombat("player") then 
		return true 
	end

	if UnitInVehicle("player") then
		return true
	end

	return false
end

function LoreKGUI.Script_OnShow()
	PlaySound(SOUNDKIT.IG_SPELLBOOK_OPEN, "SFX");

	ToggleHolidays();
	
	if IsBusy() then return end
	if LoreK_DB["settings"]["slashRead"] then
		if C_ChatInfo and C_ChatInfo.PerformEmote then
			C_ChatInfo.PerformEmote("READ", "player", true);
		else
			DoEmote("READ", "player");
		end
	end
end
function LoreKGUI.Script_OnHide()
	PlaySound(SOUNDKIT.IG_SPELLBOOK_CLOSE, "SFX");
	if LoreK_DB["settings"]["slashRead"] then
		CancelEmote();
	end
end

LoreKGUI:SetScript("OnShow", LoreKGUI.Script_OnShow);
LoreKGUI:SetScript("OnHide", LoreKGUI.Script_OnHide);
LoreKGUI:HookScript("OnShow", SetupFade);
LoreKGUI:HookScript("OnHide", CleanupFade);