local IRF2 = InvenRaidFrames2
local Option = IRF2.optionFrame
local LBO = LibStub("LibBlueOption-1.0")
local LDM = LibStub("LibDropMenu-2.0")

local _G = _G
local pairs = _G.pairs
local ipairs = _G.ipairs
local select = _G.select
local twipe = _G.table.wipe
local tinsert = _G.table.insert
local CreateFrame = _G.CreateFrame
local GetSpellInfo = _G.GetSpellInfo
local GetActiveTalentGroup = _G.GetActiveTalentGroup
local GetNumSpellTabs = _G.GetNumSpellTabs
local GetSpellTabInfo = _G.GetSpellTabInfo
local GetSpellName = _G.GetSpellName
local SpellHasRange = _G.SpellHasRange
local IsPassiveSpell = _G.IsPassiveSpell
local GetNumMacros = _G.GetNumMacros
local GetMacroInfo = _G.GetMacroInfo

function Option:CreateClickCastingMenu(menu, parent)
	local function clickCastingElementFunc(name)
		if menu.clickKeys.modKeyValue ~= name and not LBO.inCombat then
			IRF2:SetClickCastingValue(menu.clickKeys.talentGroup, menu.clickKeys.modKey, name)
			LBO:Refresh(menu.clickKeys)
		end
		LDM:CloseMenu(1)
	end
	local function clickCastingElementIcon(name)
		return name == menu.clickKeys.modKeyValue and "Interface\\Buttons\\UI-CheckBox-Check" or ""
	end
	local clickCastingDropMenu = { type = "group", args = {
		target = { type = "execute", name = "대상 선택", arg1 = "대상 선택", order = 1, func = clickCastingElementFunc, icon = clickCastingElementIcon },
		menu = { type = "execute", name = "메뉴", arg1 = "메뉴", order = 2, func = clickCastingElementFunc, icon = clickCastingElementIcon },
		inspect = { type = "execute", name = "살펴보기", arg1 = "살펴보기", order = 3, func = clickCastingElementFunc, icon = clickCastingElementIcon },
		follow = { type = "execute", name = "따라다니기", arg1 = "따라다니기", order = 4, func = clickCastingElementFunc, icon = clickCastingElementIcon },
		assist = { type = "execute", name = "대상 지원", arg1 = "대상 지원", order = 5, func = clickCastingElementFunc, icon = clickCastingElementIcon },
		focus = { type = "execute", name = "주시 대상 설정", arg1 = "주시 대상 설정", order = 6, func = clickCastingElementFunc, icon = clickCastingElementIcon },
		whisper = { type = "execute", name = "귓속말 하기", arg1 = "귓속말 하기", order = 7, func = clickCastingElementFunc, icon = clickCastingElementIcon },
		trade = { type = "execute", name = "거래 요청", arg1 = "거래 요청", order = 8, func = clickCastingElementFunc, icon = clickCastingElementIcon },
		invenMainTanker = { type = "execute", name = "인벤 포커스 지정/해제", arg1 = "인벤 포커스 지정/해제", order = 9, func = clickCastingElementFunc, icon = clickCastingElementIcon, hidden = function() return not(InvenFocusFrames and InvenFocusFrames.SetTankerUnit) end },
		commonMacro = { type = "group", name = "공통 매크로", order = 997, args = {} },
		charMacro = { type = "group", name = "캐릭터별 매크로", order = 998, args = {} },
		none = { type = "execute", name = "없음", arg1 = "없음", order = 999, func = clickCastingElementFunc, icon = clickCastingElementIcon },
	} }
	LDM:RegisterMenu("InvenRaidFrames2ClickCastingMenu", clickCastingDropMenu)
	local numButtons = 15
	local buttonOnClick = function()
		LBO:Refresh(menu.clickKeys)
		LDM:CloseMenu(1)
	end
	local buttonNames = { { name = "마우스 좌측 버튼", func = buttonOnClick }, { name = "마우스 우측 버튼", func = buttonOnClick }, { name = "마우스 휠 버튼", func = buttonOnClick } }
	for i = 4, numButtons do
		buttonNames[i] = { name = "마우스 버튼 "..i, func = buttonOnClick }
	end
	menu.buttons = LBO:CreateWidget("Menu", parent, buttonNames)
	menu.buttons:SetBackdropBorderColor(0.6, 0.6, 0.6)
	menu.buttons:SetPoint("TOPLEFT", 6, -20)
	menu.buttons:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", 150, 6)
	menu.buttons:SetValue(1)
	menu.talentGroup =  parent:CreateFontString(nil, "OVERLAY", "GameFontNormal")
	menu.talentGroup:SetPoint("BOTTOM", menu.buttons, "TOP", -2, 4)
	menu.clickKeys = CreateFrame("Frame", nil, parent)
	menu.clickKeys:SetBackdrop(menu.buttons:GetBackdrop())
	menu.clickKeys:SetBackdropBorderColor(menu.buttons:GetBackdropBorderColor())
	menu.clickKeys:SetPoint("TOPLEFT", menu.buttons, "TOPRIGHT", 0, 0)
	menu.clickKeys:SetPoint("BOTTOMRIGHT", parent, "BOTTOMRIGHT", -6, 6)
	menu.clickKeys.needUpdateSpell = true
	menu.clickKeys.needUpdateMacro = true
	local function onShow()
		if menu.clickKeys:IsVisible() and menu.clickKeys.talentGroup ~= GetActiveTalentGroup() then
			menu.clickKeys.talentGroup = GetActiveTalentGroup() or 1
			menu.talentGroup:SetFormattedText("%d 특성", menu.clickKeys.talentGroup)
			LDM:CloseMenu(1)
			LBO:Refresh(menu.clickKeys)
		end
		return nil
	end
	menu.clickKeys:SetScript("OnShow", onShow)
	menu.clickKeys:SetScript("OnEvent", function(self, event)
		onShow()
		if event == "PLAYER_TALENT_UPDATE" or event == "LEARNED_SPELL_IN_TAB" then
			self.needUpdateSpell = true
		elseif event == "UPDATE_MACROS" then
			self.needUpdateMacro = true
		end
	end)
	menu.clickKeys:SetScript("OnHide", function() LDM:CloseMenu(1) end)
	menu.clickKeys:RegisterEvent("PLAYER_TALENT_UPDATE")
	menu.clickKeys:RegisterEvent("LEARNED_SPELL_IN_TAB")
	menu.clickKeys:RegisterEvent("UPDATE_MACROS")
	menu.clickKeys:RegisterEvent("PLAYER_REGEN_DISALBED")

	local createSoulStone = GetSpellInfo(693)
	local soulStoneResurrection = GetSpellInfo(20707)
	local summonFelhunter = GetSpellInfo(691)
	local devourMagic = GetSpellInfo(19505)
	local rank1 = select(2, GetSpellInfo(5185)) or "NONE"
	local spellTable, spellTableOrder = {}, {}
	local numTab, tabName, numStart, numEnd, spellName, numMacro, numCharMacro, macroName
	local function scanSpellAndMacro()
		if menu.clickKeys.needUpdateSpell then
			numTab = GetNumSpellTabs()
			for i = 1, numTab do
				tabName, _, numStart, numEnd = GetSpellTabInfo(i)
				numEnd = numEnd + numStart
				numStart = numStart + 1
				for j = numStart, numEnd do
					spellName = GetSpellName(j, BOOKTYPE_SPELL)
					if spellName then
						if spellName == createSoulStone and soulStoneResurrection then
							spellTable[tabName] = spellTable[tabName] or {}
							spellTable[tabName][soulStoneResurrection] = true
						elseif spellName == summonFelhunter and devourMagic then
							spellTable[PET] = spellTable[PET] or {}
							spellTable[PET][devourMagic] = true
						elseif SpellHasRange(spellName) and not IsPassiveSpell(spellName) then
							spellTable[tabName] = spellTable[tabName] or {}
							spellTable[tabName][spellName] = true
						end
					end
				end
			end
			numStart, numEnd, spellName = nil
			for i = 2, numTab do
				tabName = GetSpellTabInfo(i)
				if spellTable[tabName] then
					for p in pairs(spellTable[tabName]) do
						tinsert(spellTableOrder, tabName)
						break
					end
				end
			end
			if spellTable[PET] then
				for p in pairs(spellTable[PET]) do
					tinsert(spellTableOrder, PET)
					break
				end
			end
			for index, tab in ipairs(spellTableOrder) do
				numTab = 1
				if clickCastingDropMenu.args[index] then
					clickCastingDropMenu.args[index].hidden = nil
				else
					clickCastingDropMenu.args[index] = { type = "group", name = tab, order = 900 + index, args = {} }
				end
				for name in pairs(spellTable[tab]) do
					if clickCastingDropMenu.args[index].args[numTab] then
						clickCastingDropMenu.args[index].args[numTab].hidden = nil
					else
						clickCastingDropMenu.args[index].args[numTab] = { type = "execute", func = clickCastingElementFunc, icon = clickCastingElementIcon }
					end
					clickCastingDropMenu.args[index].args[numTab].name = name
					clickCastingDropMenu.args[index].args[numTab].arg1 = name.."()"
					numTab = numTab + 1
					if select(6, GetSpellInfo(name)) == 0 and GetSpellInfo(name, rank1) then
						clickCastingDropMenu.args[index].args[numTab - 1].name = clickCastingDropMenu.args[index].args[numTab - 1].name.."(최고 레벨)"
						if clickCastingDropMenu.args[index].args[numTab] then
							clickCastingDropMenu.args[index].args[numTab].hidden = nil
						else
							clickCastingDropMenu.args[index].args[numTab] = { type = "execute", func = clickCastingElementFunc, icon = clickCastingElementIcon }
						end
						clickCastingDropMenu.args[index].args[numTab].name = name.."("..rank1..")"
						clickCastingDropMenu.args[index].args[numTab].arg1 = name.."("..rank1..")"
						numTab = numTab + 1
					end
				end
				for i = numTab, #clickCastingDropMenu.args[index].args do
					clickCastingDropMenu.args[index].args[i].hidden = true
				end
			end
			for i = #spellTableOrder + 1, #clickCastingDropMenu.args do
				clickCastingDropMenu.args[i].hidden = true
			end
			numTab, tabName = nil
			for p in pairs(spellTable) do
				twipe(spellTable[p])
			end
			twipe(spellTableOrder)
		end
		if menu.clickKeys.needUpdateMacro then
			numMacro, numCharMacro = GetNumMacros()
			if numMacro > 0 then
				clickCastingDropMenu.args.commonMacro.hidden = nil
				for i = 1, numMacro do
					macroName = GetMacroInfo(i)
					if clickCastingDropMenu.args.commonMacro.args[i] then
						clickCastingDropMenu.args.commonMacro.args[i].hidden = nil
					else
						clickCastingDropMenu.args.commonMacro.args[i] = { type = "execute", func = clickCastingElementFunc, icon = clickCastingElementIcon, order = i }
					end
					clickCastingDropMenu.args.commonMacro.args[i].name = macroName
					clickCastingDropMenu.args.commonMacro.args[i].arg1 = "[매크로] "..macroName
				end
				for i = numMacro + 1, #clickCastingDropMenu.args.commonMacro.args do
					clickCastingDropMenu.args.commonMacro.args[i].hidden = true
				end
			else
				clickCastingDropMenu.args.commonMacro.hidden = true
			end
			if numCharMacro > 0 then
				numCharMacro = numCharMacro + 36
				clickCastingDropMenu.args.charMacro.hidden = nil
				for i = 37, numCharMacro do
					macroName = GetMacroInfo(i)
					if clickCastingDropMenu.args.charMacro.args[i] then
						clickCastingDropMenu.args.charMacro.args[i].hidden = nil
					else
						clickCastingDropMenu.args.charMacro.args[i] = { type = "execute", func = clickCastingElementFunc, icon = clickCastingElementIcon, order = i }
					end
					clickCastingDropMenu.args.charMacro.args[i].name = macroName
					clickCastingDropMenu.args.charMacro.args[i].arg1 = "[매크로] "..macroName
				end
				for i = numCharMacro + 1, #clickCastingDropMenu.args.charMacro.args do
					clickCastingDropMenu.args.charMacro.args[i].hidden = true
				end
			else
				clickCastingDropMenu.args.charMacro.hidden = true
			end
		end
	end
	local function getKeyValue(modifilter)
		if menu.clickKeys.talentGroup and menu.buttons:GetValue() then
			return IRF2:GetClickCastingValue(menu.clickKeys.talentGroup, (modifilter.."BUTTON"..menu.buttons:GetValue()):upper()) or ""
		else
			return ""
		end
	end
	local function modKeyOnClick(key)
		if menu.clickKeys.talentGroup and menu.buttons:GetValue() then
			if LDM:IsOpen("InvenRaidFrames2ClickCastingMenu") then
				LDM:CloseMenu(1)
			else
				menu.clickKeys.modKey = (key:GetParent().arg1.."BUTTON"..menu.buttons:GetValue()):upper()
				menu.clickKeys.modKeyValue = key:GetParent().text:GetText() or ""
				scanSpellAndMacro()
				LDM:OpenMenu("InvenRaidFrames2ClickCastingMenu", "TOPRIGHT", key, "BOTTOMRIGHT", 0, 0)
			end
		else
			LDM:CloseMenu(1)
		end
	end
	local modifilters = { "", "alt-", "ctrl-", "shift-", "alt-ctrl-", "alt-shift-", "ctrl-shift-" }
	local modifilterNames = { "클릭", "Alt + 클릭", "Ctrl + 클릭", "Shift + 클릭", "Alt + Ctrl + 클릭", "Alt + Shift + 클릭", "Ctrl + Shift + 클릭" }
	for i, name in ipairs(modifilterNames) do
		menu.clickKeys["mod"..i] = LBO:CreateWidget("DropDown", menu.clickKeys, name, nil, nil, nil, true, getKeyValue, nil, modifilters[i])
		menu.clickKeys["mod"..i]:SetPoint("TOP", menu.clickKeys["mod"..(i - 1)], "BOTTOM", 0, -1)
		menu.clickKeys["mod"..i].button:SetScript("OnClick", modKeyOnClick)
	end
	menu.clickKeys.mod1:ClearAllPoints()
	menu.clickKeys.mod1:SetPoint("TOP", menu.clickKeys, "TOP", 0, -5)
end