local BII3 = _G[...]

local _G = _G
local type = _G.type
local pairs = _G.pairs
local ipairs = _G.ipairs
local select = _G.select
local max = _G.math.max
local wipe = _G.table.wipe
local GetItemCount = _G.GetItemCount
local GetInventoryItemID = _G.GetInventoryItemID
local tooltipText, totalCount, invCount, bagCount, bankCount, countText, invItemID
local cache = { [0] = RACE_CLASS_ONLY:format(BII3.isHorde and FACTION_ALLIANCE or FACTION_HORDE) }
local equipCache, subCache = {}, {}
local spliter, delimeter, setAll, output, output2, set = {}, "|"
local add_format = "|cff64cd3c%s|r%s%s|r"
local sub_format = "|cff64cd3c▶|r%s |cffffffff%s|r"
local unknown = "|cff64cd3c▶|r|cffff5d5d획득처 미확인|r"
local fontString = BII3:CreateFontString(nil, "OVERLAY", "GameTooltipText")
fontString:SetWidth(0)

local function addOutput(text, small, color)
	color = color or "|cffffffa4"
	text = text:gsub("_COLOR_", color)
	text = add_format:format(small and "▷" or "▶", color, text)
	if output then
		output = output.."\n"..text
	else
		output = text
	end
end

local function addSub(d, c1, c2)
	if c1 and c2 then
		if d then
			if c1:find("%)") then
				c1 = c1:gsub("%)", " "..d..")", 1)
			else
				c1 = c1.."("..d..")"
			end
		end
		if subCache[c1] then
			subCache[c1] = subCache[c1]..", "..c2
		else
			subCache[c1] = c2
		end
	end
end

local function replaceCategory2nd(text)
	if text:find("$C[A-Z0-9a-z][0-9a-z][0-9a-z]") then
		local c = text:match("$C([A-Z0-9a-z][0-9a-z][0-9a-z])")
		local n = select(2, BII3:GetCategoryName(c)) or c
		if n ~= c then
			n:gsub("%((%d+)인%)", "")
			if not n:find("|r") then
				n = "_COLOR_"..n.."|r"
			end
		end
		text = text:gsub("$C"..c, n)
		return replaceCategory2nd(text)
	else
		return text
	end
end

local function replaceCategory3rd(text)
	if text:find("$c[A-Z0-9a-z][0-9a-z][0-9a-z]") then
		local c = text:match("$c([A-Z0-9a-z][0-9a-z][0-9a-z])")
		text = text:gsub("$c"..c, select(3, BII3:GetCategoryName(c)) or c)
		return replaceCategory3rd(text)
	else
		return text
	end
end

local function replaceItemName(text)
	if text:find("$i(%d+)") then
		local c = text:match("$i(%d+)")
		text = text:gsub("$i"..c, BII3:GetItemColorName(tonumber(c) or 0))
		return replaceItemName(text)
	else
		return text
	end
end

local function replacePostposition(text, p1, p2)
	local s, e = text:find(p1)
	if s then
		return ("%s"..p2.."%s"):format(text:sub(1, s - 1), text:sub(e + 1))
	end
	return text
end

local function replaceText(text)
	text = BII3:ReplaceFactionText(text)
	text = replaceCategory2nd(text)
	text = replaceCategory3rd(text)
	text = replaceItemName(text)
	text = replacePostposition(text, "<으로>", "|1으로;로;")
	text = replacePostposition(text, "<이가>", "|1이;가;")
	text = replacePostposition(text, "<을를>", "|1을;를;")
	return text
end

local function getCache(id)
	if type(cache[id]) == "string" then
		return cache[id]
	elseif type(cache[id]) == "number" and type(cache[cache[id]]) == "string" then
		return cache[cache[id]]
	else
		return nil
	end
end

local function parserInfo(dtype, dtext)
	if dtype == "X" then
		-- 강제 툴팁
		setAll, output = true
		addOutput(replaceText(dtext))
		wipe(subCache)
		return true
	elseif dtype == "C" then
		-- 추가 툴팁 (분류 2 사용)
		addOutput(replaceText(dtext))
	elseif dtype == "c" then
		-- 추가 툴팁 (분류 3 사용)
		dtext = replaceCategory2nd(dtext)
		dtext = replaceCategory3rd(dtext)
		dtext = replaceItemName(dtext)
		addOutput(dtext, true, "|cff76eec6")
	elseif dtype == "R" or dtype == "D" then
		-- 일반 난이도 던전/레이드 툴팁
		addSub(nil, select(2, BII3:GetCategoryName(dtext)))
	elseif dtype == "r" then
		-- 하드 난이도 레이드 툴팁
		addSub("하드", select(2, BII3:GetCategoryName(dtext)))
	elseif dtype == "d" then
		-- 영웅 난이도 던전 툴팁
		addSub("영웅", select(2, BII3:GetCategoryName(dtext)))
	elseif dtype == "A" then
		-- 일반 툴팁
		local code, desc = ("@"):split(dtext)
		code = code and select(2, BII3:GetCategoryName(code))
		if code and desc then
			addOutput(code.." "..replaceText(desc), nil, "|cffffffff")
		elseif code then
			addOutput(code, nil, "|cffffffff")
		elseif desc then
			addOutput(replaceText(desc), nil, "|cffffffff")
		end
	elseif dtype == "S" then
		-- 세트 툴팁
		dtext = select(2, BII3:GetCategoryName(dtext))
		if dtext then
			addOutput(dtext, true, "|cffffffff")
		end
	elseif dtype == "s" then
		dtype, dtext = ("@"):split(dtext)
		dtype = dtype and tonumber(dtype) or nil
		set = dtype and getCache(dtype) or unknown
		if set then
			dtype = BII3:GetItemColorName(dtype)
			if dtext then
				dtype = dtype.." + "..replaceText(dtext)
			end
			dtype = " ("..dtype..")"
			set = set:gsub("\n", dtype.."\n")..dtype
			if output then
				output = output.."\n"..set
			else
				output = set
			end
		end
	elseif dtype == "Q" then
		-- 퀘스트 툴팁
		local code, zone, level, name = ("@"):split(dtext)
		if code and name then
			code = select(3, BII3:GetCategoryName(code))
			if code then
				addOutput(code.."|r |cff9ac0cd"..BII3:ReplaceFactionText(zone), nil, "|cffbfefff")
				addOutput("["..BII3:ReplaceFactionText(level).."] "..BII3:ReplaceFactionText(name), true, "|cff76eec6")
			end
		end
	end
	return nil
end

local function getTooltipText(id)
	if cache[id] then
		return getCache(id)
	end
	local itemDB = BII3.itemDB[id]
	if itemDB then
		if type(itemDB) == "number" then
			if type(cache[itemDB]) == "string" then
				cache[id] = itemDB
				return cache[itemDB]
			elseif type(BII3.itemDB[itemDB]) == "string" then
				cache[id] = itemDB
				id = itemDB
				itemDB = BII3.itemDB[itemDB]
			else
				return nil
			end
		elseif type(itemDB) ~= "string" then
			return nil
		end
		if itemDB:find("^a") then
			if BII3.isHorde then
				cache[id] = 0
				return cache[0]
			else
				itemDB = itemDB:gsub("^a", ""):gsub("^|", "")
			end
		elseif BII3.itemDB[id]:find("^h") then
			if BII3.isHorde then
				itemDB = itemDB:gsub("^h", ""):gsub("^|", "")
			else
				cache[id] = 0
				return cache[0]
			end
		end
		if itemDB:find("s_(%d+)") then
			setAll, output, setoutput = nil
			getTooltipText(tonumber(itemDB:match("s_(%d+)")))
		end
		setAll, output, setoutput = nil
		spliter[1], spliter[2], spliter[3], spliter[4], spliter[5], spliter[6], spliter[7], spliter[8], spliter[9], spliter[10], spliter[11], spliter[12], spliter[13], spliter[14], spliter[15], spliter[16], spliter[17], spliter[18], spliter[19], spliter[20] = ("|"):split(itemDB)
		for _, info in ipairs(spliter) do
			if parserInfo(info:match("([A-Za-z])_(.+)")) then
				break
			end
		end
		output2, output = output, nil
		for zone, detail in pairs(subCache) do
			detail = sub_format:format(zone, detail)
			if output then
				output = output.."\n"..detail
			else
				output = detail
			end
			subCache[zone] = nil
		end
		if output2 and output then
			cache[id] = output.."\n"..output2
			output, output2 = nil
			return cache[id]
		elseif output then
			cache[id] = output
			output = nil
			return cache[id]
		elseif output2 then
			cache[id] = output2
			output2 = nil
			return cache[id]
		else
			cache[id] = true
		end
	end
	return nil
end

local function getStringWidth(text)
	fontString:SetText(text)
	return fontString:GetWidth()
end

local count_format = "|cff64cd3c▷|cffffff00%s|r"

function BII3:ProcessTooltip(tooltip, _, _, id)
	if self.db.drop then
		tooltipText = getTooltipText(id)
		if tooltipText then
			if getStringWidth(tooltipText) > 350 then
				tooltip:SetMinimumWidth(max(tooltip:GetMinimumWidth() or 350, 350))
				tooltip:AddLine(tooltipText, 1, 1, 1, 1)
			else
				tooltip:AddLine(tooltipText, 1, 1, 1)
			end
			tooltipText = nil
		end
	end
	if self.db.count and id > 0 then
		totalCount = GetItemCount(id, true) or 0
		if totalCount > 0 then
			bagCount = GetItemCount(id) or 0
			invCount = equipCache[id] or 0
			bankCount = totalCount - bagCount
			bagCount = bagCount - invCount
			if totalCount == 1 then
				if bankCount == 1 then
					tooltip:AddLine(count_format:format("아이템 보유중(은행)"))
				elseif bagCount == 1 then
					tooltip:AddLine(count_format:format("아이템 보유중(가방)"))
				else
					tooltip:AddLine(count_format:format("아이템 착용중"))
				end
			elseif totalCount > 1 then
				countText = ("총 %d개 보유중("):format(totalCount)
				if invCount > 0 then
					countText = ("%s착용 %d"):format(countText, invCount)
				end
				if bagCount > 0 then
					if invCount > 0 then
						countText = ("%s, 가방 %d"):format(countText, bagCount)
					else
						countText = ("%s가방 %d"):format(countText, bagCount)
					end
				end
				if bankCount > 0 then
					if bagCount > 0 or invCount > 0 then
						countText = ("%s, 은행 %d"):format(countText, bankCount)
					else
						countText = ("%s은행 %d"):format(countText, bankCount)
					end
				end
				tooltip:AddLine(count_format:format(countText..")"))
			end
		end
		totalCount, invCount, bagCount, bankCount, countText = nil
	end
end

function BII3:UNIT_INVENTORY_CHANGED()
	wipe(equipCache)
	for i = INVSLOT_FIRST_EQUIPPED, INVSLOT_LAST_EQUIPPED do
		invItemID = GetInventoryItemID("player", i)
		if invItemID then
			equipCache[invItemID] = (equipCache[invItemID] or 0) + 1
		end
	end
	invItemID = nil
end

BII3.PLAYER_ENTERING_WORLD = BII3.UNIT_INVENTORY_CHANGED
BII3:RegisterEvent("PLAYER_ENTERING_WORLD")
BII3:RegisterEvent("UNIT_INVENTORY_CHANGED")