local SLE, T, E, L, V, P, G = unpack(select(2, ...))
local DD = SLE:NewModule("Dropdowns", "AceEvent-3.0")

DD.RegisteredMenus = {}

--Cache global variables
local tinsert = tinsert
--WoW API / Variables
local CreateFrame = CreateFrame
local ToggleFrame = ToggleFrame
local GetCursorPosition = GetCursorPosition

--Global variables that we don't cache, list them here for the mikk's Find Globals script
-- GLOBALS: UIParent, UISpecialFrames,
local _G = _G

local PADDING = 10
local BUTTON_HEIGHT = 16
local BUTTON_WIDTH = 135
local TITLE_OFFSET = 10

local function OnClick(btn)
	if btn.func then btn.func() end

	btn:GetParent():Hide()
end

local function OnEnter(btn)
	if not btn.nohighlight then btn.hoverTex:Show() end
	if btn.UseTooltip then
		_G["GameTooltip"]:SetOwner(btn, "ANCHOR_BOTTOMLEFT", -9)
		if btn.TooltipText then
			_G["GameTooltip"]:SetText(btn.TooltipText)
		elseif btn.secure.isToy then
			_G["GameTooltip"]:SetToyByItemID(btn.secure.ID)
		elseif btn.secure.buttonType == "item" then
			_G["GameTooltip"]:SetItemByID(btn.secure.ID)
		elseif btn.secure.buttonType == "spell" then
			_G["GameTooltip"]:SetSpellByID(btn.secure.ID)
		end
		_G["GameTooltip"]:Show()
	end
end

local function OnLeave(btn)
	_G["GameTooltip"]:Hide()
	btn.hoverTex:Hide()
end

local function CreateListButton(frame)
	local button = CreateFrame("Button", nil, frame, "SecureActionButtonTemplate")

	button.hoverTex = button:CreateTexture(nil, 'OVERLAY')
	button.hoverTex:SetAllPoints()
	button.hoverTex:SetTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]])
	button.hoverTex:SetBlendMode("ADD")
	button.hoverTex:Hide()

	button.text = button:CreateFontString(nil, 'BORDER')
	button.text:SetAllPoints()
	button.text:FontTemplate()

	button:SetScript("OnEnter", OnEnter)
	button:SetScript("OnLeave", OnLeave)
	button:HookScript("OnClick", OnClick)

	return button
end

function SLE:DropdownList(list, frame, customWidth, justify)
	for i=1, #list do
		frame.buttons[i] = frame.buttons[i] or CreateListButton(frame)
		local btn = frame.buttons[i]

		btn.func = list[i].func or nil
		btn.nohighlight = list[i].nohighlight
		btn.text:SetJustifyH(justify or "LEFT")
		btn:Show()
		btn:Height(BUTTON_HEIGHT)

		local icon = ""
		if list[i].icon then
			icon = "|T"..list[i].icon..":14:14:0:0:64:64:4:60:4:60|t "
		end

		btn.text:SetText(icon..list[i].text)
		if list[i].title then
			frame.TitleCount = frame.TitleCount + 1
			btn.text:SetTextColor(0.98, 0.95, 0.05)
			if list[i].ending or i == 1 or list[i-1].title then
				frame.AddOffset = frame.AddOffset + 1
			end
		else
			btn.text:SetTextColor(1, 1, 1)
		end

		if customWidth and customWidth == "auto" then
			if frame.maxWidth < btn.text:GetStringWidth() then
				frame.maxWidth = btn.text:GetStringWidth()
				frame.TitleCount = 0
				frame.AddOffset = 0
				SLE:DropdownList(list, frame, customWidth, justify)
				return
			end
			btn:Width(frame.maxWidth)
		else
			btn:Width(customWidth or BUTTON_WIDTH)
		end

		if list[i].secure then
			btn:SetAttribute("type", nil)
			-- btn:SetAttribute("item", nil)
			-- btn:SetAttribute("spell", nil)
			-- btn:SetAttribute("macrotext", nil)
			btn.secure = list[i].secure
			btn:SetAttribute("type", btn.secure.buttonType)
			if btn.secure.buttonType == "item" then
				local name = T.GetItemInfo(btn.secure.ID)
				btn:SetAttribute("item", name)
			elseif btn.secure.buttonType == "spell" then
				local name = T.GetSpellInfo(btn.secure.ID)
				btn:SetAttribute("spell", name)
			elseif btn.secure.buttonType == "macro" then
				btn:SetAttribute("macrotext", btn.secure.ID)
			else
				SLE:Print("Wrong argument for button type: "..btn.secure.buttonType, "error")
			end
		end
		btn.UseTooltip = list[i].UseTooltip
		if list[i].TooltipText then btn.TooltipText = list[i].TooltipText end

		local MARGIN = 10
		if justify then
			if justify == "RIGHT" then MARGIN = -10 end
			if justify == "CENTER" then MARGIN = 0 end
		end

		if i == 1 then
			btn:Point("TOPLEFT", frame, "TOPLEFT", MARGIN, -PADDING)
		else
			btn:Point("TOPLEFT", frame.buttons[i-1], "BOTTOMLEFT", 0, -((list[i-1].title or list[i].title) and TITLE_OFFSET or 0))
		end
	end
end

function SLE:DropDown(list, frame, MenuAnchor, FramePoint, xOffset, yOffset, parent, customWidth, justify)
	if T.InCombatLockdown() then return end
	frame.maxWidth = BUTTON_WIDTH
	frame.TitleCount = 0
	frame.AddOffset = 0
	if not frame.buttons then
		frame.buttons = {}
		frame:SetFrameStrata("DIALOG")
		frame:SetClampedToScreen(true)
		T.tinsert(UISpecialFrames, frame:GetName())
		frame:Hide()
	end
	for i=1, #frame.buttons do
		local btn = frame.buttons[i]
		btn.UseTooltip = false
		btn.func = nil
		btn.secure = nil
		btn.TooltipText = nil
		btn.text:SetText("")
		btn:Hide()
	end
	if not frame:IsShown() then
		xOffset = xOffset or 0
		yOffset = yOffset or 0

		if not parent then FramePoint = "CURSOR" end
		SLE:DropdownList(list, frame, customWidth, justify)

		frame:Height((#list * BUTTON_HEIGHT) + PADDING * 2 + frame.TitleCount * (2 * TITLE_OFFSET) - frame.AddOffset * TITLE_OFFSET)
		if customWidth and customWidth == "auto" then
			frame:Width(frame.maxWidth + PADDING * 2)
		else
			frame:Width(customWidth or (BUTTON_WIDTH + PADDING * 2))
		end

		frame:ClearAllPoints()
		if FramePoint == "CURSOR" then
			local UIScale = UIParent:GetScale();
			local x, y = GetCursorPosition();
			x = x/UIScale
			y = y/UIScale
			frame:Point(MenuAnchor, UIParent, "BOTTOMLEFT", x + xOffset, y + yOffset)
		else
			frame:Point(MenuAnchor, parent, FramePoint, xOffset, yOffset)
		end
	end
	ToggleFrame(frame)
end

function DD:GetCooldown(CDtype, id)
	local cd, formatID
	local start, duration = T["Get"..CDtype.."Cooldown"](id)
	if start > 0 then
		cd = duration - (T.GetTime() - start)
		cd, formatID = E:GetTimeInfo(cd, 0)
		cd = T.format(E.TimeFormats[formatID][3], cd)
		return cd
	end
	return nil
end

function DD:HideMenus(event)
	if event == "PLAYER_ENTERING_WORLD" then self:UnregisterEvent(event) end
	for name, menu in T.pairs(DD.RegisteredMenus) do
		menu:Hide()
	end
end

function DD:RegisterMenu(menu)
	local name = menu:GetName()
	if name then
		DD.RegisteredMenus[name] = menu
	else
		SLE:Print("Dropdown not registered. Please check if it has a name.")
	end
end

function DD:Initialize()
	self:RegisterEvent("PLAYER_ENTERING_WORLD", "HideMenus")
	self:RegisterEvent("LOADING_SCREEN_DISABLED", "HideMenus")
	self:RegisterEvent("PLAYER_REGEN_DISABLED", "HideMenus")
end

SLE:RegisterModule(DD:GetName())
