--- @class StdUi
local StdUi = LibStub and LibStub('StdUi', true);
if not StdUi then
	return
end

local module, version = 'Tooltip', 3;
if not StdUi:UpgradeNeeded(module, version) then
	return
end

StdUi.tooltips = {};
StdUi.frameTooltips = {};

----------------------------------------------------
--- Tooltip
----------------------------------------------------

local TooltipEvents = {
	OnEnter = function(self)
		local tip = self.stdUiTooltip;
		tip:SetOwner(tip.owner or UIParent, tip.anchor or 'ANCHOR_NONE');

		if type(tip.text) == 'string' then
			tip:SetText(tip.text,
				tip.stdUi.config.font.color.r,
				tip.stdUi.config.font.color.g,
				tip.stdUi.config.font.color.b,
				tip.stdUi.config.font.color.a
			);
		elseif type(tip.text) == 'function' then
			tip.text(tip);
		end

		tip:Show();
		tip:ClearAllPoints();
		tip.stdUi:GlueOpposite(tip, tip.owner, 0, 0, tip.anchor);
	end,

	OnLeave = function(self)
		local tip = self.stdUiTooltip;
		tip:Hide();
	end
}

--- Standard blizzard tooltip
---@return GameTooltip
function StdUi:Tooltip(owner, text, tooltipName, anchor, automatic)
	--- @type GameTooltip
	local tip;

	if tooltipName and self.tooltips[tooltipName] then
		tip = self.tooltips[tooltipName];
	else
		tip = CreateFrame('GameTooltip', tooltipName, UIParent, 'GameTooltipTemplate');
		self:ApplyBackdrop(tip, 'panel');
	end

	tip.owner = owner;
	tip.anchor = anchor;
	tip.text = text;
	tip.stdUi = self;
	owner.stdUiTooltip = tip;

	if automatic then
		for k, v in pairs(TooltipEvents) do
			owner:HookScript(k, v);
		end
	end

	return tip;
end

----------------------------------------------------
--- Tooltip
----------------------------------------------------
---@class FrameTooltipMethods
local FrameTooltipMethods = {
	SetText         = function(self, text, r, g, b)
		if r and g and b then
			text = self.stdUi.Util.WrapTextInColor(text, r, g, b, 1);
		end
		self.text:SetText(text);

		self:RecalculateSize();
	end,

	GetText         = function(self)
		return self.text:GetText();
	end,

	AddLine         = function(self, text, r, g, b)
		local txt = self:GetText();
		if not txt then
			txt = '';
		else
			txt = txt .. '\n'
		end
		if r and g and b then
			text = self.stdUi.Util.WrapTextInColor(text, r, g, b, 1);
		end
		self:SetText(txt .. text);
	end,

	RecalculateSize = function(self)
		self:SetSize(
			self.text:GetWidth() + self.padding * 2,
			self.text:GetHeight() + self.padding * 2
		);
	end
};

local OnShowFrameTooltip = function(self)
	self:RecalculateSize();
	self:ClearAllPoints();
	self.stdUi:GlueOpposite(self, self.owner, 0, 0, self.anchor);
end

local FrameTooltipEvents = {
	OnEnter = function(self)
		self.stdUiTooltip:Show();
	end,

	OnLeave = function(self)
		self.stdUiTooltip:Hide();
	end,
};

function StdUi:FrameTooltip(owner, text, tooltipName, anchor, automatic, manualPosition)
	local tip; ---@class FrameTooltip : Frame, FrameTooltipMethods

	if tooltipName and self.frameTooltips[tooltipName] then
		tip = self.frameTooltips[tooltipName];
	else
		tip = self:Panel(owner, 10, 10);
		tip.stdUi = self;
		tip:SetFrameStrata('TOOLTIP');
		self:ApplyBackdrop(tip, 'panel');

		tip.padding = self.config.tooltip.padding;

		tip.text = self:FontString(tip, '');
		self:GlueTop(tip.text, tip, tip.padding, -tip.padding, 'LEFT');

		for k, v in pairs(FrameTooltipMethods) do
			tip[k] = v;
		end

		if not manualPosition then
			hooksecurefunc(tip, 'Show', OnShowFrameTooltip);
		end
	end

	tip.owner = owner;
	tip.anchor = anchor;

	owner.stdUiTooltip = tip;

	if type(text) == 'string' then
		tip:SetText(text);
	elseif type(text) == 'function' then
		text(tip);
	end

	if automatic then
		for k, v in pairs(FrameTooltipEvents) do
			owner:HookScript(k, v);
		end
	end

	return tip;
end

StdUi:RegisterModule(module, version);