AzeriteTooltip = LibStub("AceAddon-3.0"):NewAddon("AzeriteTooltip", "AceEvent-3.0", "AceHook-3.0")

local locationIDs = {
	["Head"] = 1,
	["Shoulder"] = 3,
	["Chest"] = 5,
}

local itemEquipLocToSlot = {
	["INVTYPE_HEAD"] = 1,
	["INVTYPE_SHOULDER"] = 3,
	["INVTYPE_CHEST"] = 5,
	["INVTYPE_ROBE"] = 5
}

local rings = {
	1,
	2,
}

local addText = ""

StaticPopupDialogs["ReloadUI_Popup"] = {
	text = "Reload your UI to apply changes?",
	button1 = "Reload",
	button2 = "Later",
	OnAccept = function()
	    ReloadUI()
	end,
	timeout = 0,
	whileDead = true,
	hideOnEscape = true,
	preferredIndex = 3,
}

local defaults_settings = {
    profile = {
        removeblizzard = false,	--bf@178.com
        onlyspec = false,
        compact = true,			--bf@178.com
        bags = true,
		icon_anchor = "BOTTOMLEFT",
        paperdoll = true,
    }
}

function AzeriteTooltip:OnInitialize()
	self.db = LibStub("AceDB-3.0"):New("AzeriteTooltipDB", defaults_settings, true)
	self.settings = self.db.profile

	self:SetupOptions()

    LibStub("AceConfigDialog-3.0"):AddToBlizOptions("AzeriteTooltip", "AzeriteTooltip")
end

function AzeriteTooltip:SetupOptions()
	self.options = {
		name = "AzeriteTooltip",
		descStyle = "inline",
		type = "group",
		childGroups = "tab",
		args = {
			desc = {
				type = "description",
				name = "Lightweight addon that shows azerite traits on tooltip/gear.",
				fontSize = "medium",
				order = 1
			},
			author = {
				type = "description",
				name = "\n|cffffd100Author: |r Kygo @ EU-Hyjal",
				order = 2
			},
			version = {
				type = "description",
				name = "|cffffd100Version: |r" .. GetAddOnMetadata("AzeriteTooltip", "Version") .."\n",
				order = 3
			},
			removeblizzard = {
                name = "Remove Blizzard Text",
                desc = "|cffaaaaaaReplace blizzard's default text. |r",
                descStyle = "inline",
                width = "full",
                type = "toggle",
                order = 4,
                set = function(info,val)
                    self.settings.removeblizzard = val
                end,
                get = function(info) return self.settings.removeblizzard end
            },
            onlyspec = {
                name = "Only Spec",
                desc = "|cffaaaaaaShow only traits for your current specialization. |r",
                descStyle = "inline",
                width = "full",
                type = "toggle",
                order = 5,
                set = function(info,val)
                    self.settings.onlyspec = val
                end,
                get = function(info) return self.settings.onlyspec end
            },
            compact = {
                name = "Compact Mode",
                desc = "|cffaaaaaaTraits will show in a more compact layout. |r",
                descStyle = "inline",
                width = "full",
                type = "toggle",
                order = 6,
                set = function(info,val)
                    self.settings.compact = val
                end,
                get = function(info) return self.settings.compact end
            },
            bags = {
                name = "Show traits in bags",
                desc = "|cffaaaaaaShow two main traits on gear in bags (works only with Blizzard Bags and Bagnon). |r",
                descStyle = "inline",
                width = "full",
                type = "toggle",
                order = 7,
                set = function(info,val)
                	StaticPopup_Show("ReloadUI_Popup")
                    self.settings.bags = val
                end,
                get = function(info) return self.settings.bags end
            },
            paperdoll = {
                name = "Show traits in character frame",
                desc = "|cffaaaaaaShow two main traits on gear on character frame. |r",
                descStyle = "inline",
                width = "full",
                type = "toggle",
                order = 8,
                set = function(info,val)
                	StaticPopup_Show("ReloadUI_Popup")
                    self.settings.paperdoll = val
                end,
                get = function(info) return self.settings.paperdoll end
            },
			icon_anchor = {
				type = "select",
				name = "Icon Anchor",
				style = "dropdown",
				values = {
					["TOPLEFT"] = "TOP", -- 0
					["BOTTOMLEFT"] = "BOTTOM", -- 1

				},
				order = 9,
				set = function(info,val)
					self.settings.icon_anchor = val
				end,
				get = function(info)
					return self.settings.icon_anchor
				end
			},
		}
	}

    LibStub("AceConfig-3.0"):RegisterOptionsTable("AzeriteTooltip", self.options)
end

function AzeriteTooltip:OnEnable()
    self:SecureHook('PaperDollItemSlotButton_Update')
    self:SecureHook('EquipmentFlyout_DisplayButton')
    self:SecureHook('ContainerFrame_Update')

    if IsAddOnLoaded("Bagnon") then
    	hooksecurefunc(Bagnon.Item, "Update", function(self)
    		if not AzeriteTooltip.db.profile.bags then return end

    		AzeriteTooltip:SetContainerAzerite(self)
    	end)
    end

    self:SecureHookScript(GameTooltip, 'OnTooltipSetItem', 'OnTooltipSetItem')
    self:SecureHookScript(ItemRefTooltip, 'OnTooltipSetItem', 'OnTooltipSetItem')
    self:SecureHookScript(ShoppingTooltip1, 'OnTooltipSetItem', 'OnTooltipSetItem')
    self:SecureHookScript(EmbeddedItemTooltip, 'OnTooltipSetItem', 'OnTooltipSetItem')
end

function AzeriteTooltip:GetSpellID(powerID)
	local powerInfo = C_AzeriteEmpoweredItem.GetPowerInfo(powerID)
  	if (powerInfo) then
    	local azeriteSpellID = powerInfo["spellID"]
    	return azeriteSpellID
  	end
end

function AzeriteTooltip:HasUnselectedPower(tooltip)
	local AzeriteUnlock = strsplit("%d", AZERITE_POWER_UNLOCKED_AT_LEVEL)
	for i = 8, tooltip:NumLines() do
		local left = _G[tooltip:GetName().."TextLeft"..i]
		local text = left:GetText()
        if text and ( text:find(AzeriteUnlock) or text:find(NEW_AZERITE_POWER_AVAILABLE) ) then
        	return true
        end
    end
end

function AzeriteTooltip:ScanSelectedTraits(tooltip, powerName)
	local empowered = GetSpellInfo(263978)
	for i = 8, tooltip:NumLines() do
		local left = _G[tooltip:GetName().."TextLeft"..i]
		local text = left:GetText()
		local newText
		local newPowerName
		if text and text:find("-") then
			newText = string.gsub(text, "-", " ")
		end
		if powerName:find("-") then
			newPowerName = string.gsub(powerName, "-", " ")
		end
        if text and text:find(powerName) then
        	return true
       	elseif (newText and newPowerName and newText:match(newPowerName)) then
       		return true
        elseif (powerName == empowered and not self:HasUnselectedPower(tooltip)) then
         	return true
        end
    end
end

function AzeriteTooltip:GetAzeriteLevel()
	local azeriteItemLocation = C_AzeriteItem.FindActiveAzeriteItem()
	local azeriteItemPowerLevel = azeriteItemLocation and not AzeriteUtil.IsAzeriteItemLocationBankBag(azeriteItemLocation) and C_AzeriteItem.GetPowerLevel(azeriteItemLocation) or 0;
	return azeriteItemPowerLevel
end

function AzeriteTooltip:ClearBlizzardText(tooltip)
	local textLeft = tooltip.textLeft
	if not textLeft then
		local tooltipName = tooltip:GetName()
		textLeft = setmetatable({}, { __index = function(t, i)
			local line = _G[tooltipName .. "TextLeft" .. i]
			t[i] = line
			return line
		end })
		tooltip.textLeft = textLeft
	end
	for i = 7, tooltip:NumLines() do
		if textLeft then
			local line = textLeft[i]
			local text = line:GetText()
			local r, g, b = line:GetTextColor()
			if text then
				local ActiveAzeritePowers = strsplit("(%d/%d)", CURRENTLY_SELECTED_AZERITE_POWERS) -- Active Azerite Powers (%d/%d)
				local AzeritePowers = strsplit("(0/%d)", TOOLTIP_AZERITE_UNLOCK_LEVELS) -- Azerite Powers (0/%d)
				local AzeriteUnlock = strsplit("%d", AZERITE_POWER_UNLOCKED_AT_LEVEL) -- Unlocked at Heart of Azeroth Level %d
				local Durability = strsplit("%d / %d", DURABILITY_TEMPLATE)
				local ReqLevel = strsplit("%d", ITEM_MIN_LEVEL)

				if text:match(NEW_AZERITE_POWER_AVAILABLE) then
					line:SetText("")
				end

				if text:find(AzeriteUnlock) then
					line:SetText("")
				end

				if text:find(Durability) or text:find(ReqLevel) then
					textLeft[i-1]:SetText("")
				end

				if text:find(ActiveAzeritePowers) then
                    textLeft[i-1]:SetText("")
                    line:SetText("")
					textLeft[i+1]:SetText(addText)
				elseif (text:find(AzeritePowers) and not text:find(">")) then
                    textLeft[i-1]:SetText("")
                    line:SetText("")
					textLeft[i+1]:SetText(addText)
				-- 8.1 FIX --
				elseif text:find(AZERITE_EMPOWERED_ITEM_FULLY_UPGRADED) then
					textLeft[i-1]:SetText("")
					line:SetText(addText)
					textLeft[i+1]:SetText("")
				end
			end
		end
	end
end

function AzeriteTooltip:RemovePowerText(tooltip, powerName)
	local textLeft = tooltip.textLeft
	if not textLeft then
		local tooltipName = tooltip:GetName()
		textLeft = setmetatable({}, { __index = function(t, i)
			local line = _G[tooltipName .. "TextLeft" .. i]
			t[i] = line
			return line
		end })
		tooltip.textLeft = textLeft
	end
	for i = 7, tooltip:NumLines() do
		if textLeft then
			local enchanted = strsplit("%d", ENCHANTED_TOOLTIP_LINE)
			local use = strsplit("%d", ITEM_SPELL_TRIGGER_ONUSE)
			local line = textLeft[i]
			local text = line:GetText()
			local r, g, b = line:GetTextColor()
			local newText
			local newPowerName
			if text and text:find("-") then
				newText = string.gsub(text, "-", " ")
			end
			if powerName:find("-") then
				newPowerName = string.gsub(powerName, "-", " ")
			end
			if text then
				if text:match(CURRENTLY_SELECTED_AZERITE_POWERS_INSPECT) then return end
				if text:find("- "..powerName) then
					line:SetText("")
				elseif (newText and newPowerName and newText:match(newPowerName)) then
       				line:SetText("")
				end
				if ( r < 0.1 and g > 0.9 and b < 0.1 and not text:find(">") and not text:find(ITEM_SPELL_TRIGGER_ONEQUIP) and not text:find(enchanted) and not text:find(use) ) then
					line:SetText("")
				end
			end
		end
	end
end

function AzeriteTooltip:BuildTooltip(self)
	local name, link = self:GetItem()
  	if not name then return end

  	if C_AzeriteEmpoweredItem.IsAzeriteEmpoweredItemByID(link) then

  		addText = ""

		local currentLevel = AzeriteTooltip:GetAzeriteLevel()

		local specID = GetSpecializationInfo(GetSpecialization())
		local allTierInfo = C_AzeriteEmpoweredItem.GetAllTierInfoByItemID(link)

		if not allTierInfo then return end

		local activePowers = {}
		local activeAzeriteTrait = false

		if AzeriteTooltip.db.profile.compact then
			for j=1, 5 do
				if not allTierInfo[j] then break end

				local tierLevel = allTierInfo[j]["unlockLevel"]
				local azeritePowerID = allTierInfo[j]["azeritePowerIDs"][1]

				if not allTierInfo[1]["azeritePowerIDs"][1] then return end

				local azeriteTooltipText = " "
				for i, _ in pairs(allTierInfo[j]["azeritePowerIDs"]) do
					local azeritePowerID = allTierInfo[j]["azeritePowerIDs"][i]
					local azeriteSpellID = AzeriteTooltip:GetSpellID(azeritePowerID)
					local azeritePowerName, _, icon = GetSpellInfo(azeriteSpellID)

					if tierLevel <= currentLevel then
						if AzeriteTooltip:ScanSelectedTraits(self, azeritePowerName) then
							local azeriteIcon = '|T'..icon..':24:24:0:0:64:64:4:60:4:60:255:255:255|t'
							azeriteTooltipText = azeriteTooltipText.."  >"..azeriteIcon.."<"

							tinsert(activePowers, {name = azeritePowerName})
							activeAzeriteTrait = true
						elseif C_AzeriteEmpoweredItem.IsPowerAvailableForSpec(azeritePowerID, specID) then
							local azeriteIcon = '|T'..icon..':24:24:0:0:64:64:4:60:4:60:255:255:255|t'
							azeriteTooltipText = azeriteTooltipText.."  "..azeriteIcon
						elseif not AzeriteTooltip.db.profile.onlyspec or IsControlKeyDown() then
							local azeriteIcon = '|T'..icon..':24:24:0:0:64:64:4:60:4:60:150:150:150|t'
							azeriteTooltipText = azeriteTooltipText.."  "..azeriteIcon
						end
					elseif C_AzeriteEmpoweredItem.IsPowerAvailableForSpec(azeritePowerID, specID) then
						local azeriteIcon = '|T'..icon..':24:24:0:0:64:64:4:60:4:60:150:150:150|t'
						azeriteTooltipText = azeriteTooltipText.."  "..azeriteIcon
					elseif not AzeriteTooltip.db.profile.onlyspec or IsControlKeyDown() then
						local azeriteIcon = '|T'..icon..':24:24:0:0:64:64:4:60:4:60:150:150:150|t'
						azeriteTooltipText = azeriteTooltipText.."  "..azeriteIcon
					end
				end

				if tierLevel <= currentLevel then
					if j > 1 then
						addText = addText.."\n \n|cFFffcc00Level "..tierLevel..azeriteTooltipText.."|r"
					else
						addText = addText.."\n|cFFffcc00Level "..tierLevel..azeriteTooltipText.."|r"
					end
				else
					if j > 1 then
						addText = addText.."\n \n|cFF7a7a7aLevel "..tierLevel..azeriteTooltipText.."|r"
					else
						addText = addText.."\n|cFF7a7a7aLevel "..tierLevel..azeriteTooltipText.."|r"
					end
				end

			end
		else
			for j=1, 5 do
				if not allTierInfo[j] then break end

				local tierLevel = allTierInfo[j]["unlockLevel"]
				local azeritePowerID = allTierInfo[j]["azeritePowerIDs"][1]

				if not allTierInfo[1]["azeritePowerIDs"][1] then return end

				local r, g, b

                if tierLevel <= currentLevel then
                    r, g, b = 1, 0.8, 0
                else
                    r, g, b = 0.5, 0.5, 0.5
                end

                local rgb = ("ff%.2x%.2x%.2x"):format(r*255, g*255, b*255)

                if j > 1 then
					addText = addText.. "\n\n|c" .. rgb .. format(" Level %d", tierLevel) .. "|r\n"
				else
					addText = addText.. "\n|c" .. rgb .. format(" Level %d", tierLevel) .. "|r\n"
				end

				for i, v in pairs(allTierInfo[j]["azeritePowerIDs"]) do
					local azeritePowerID = allTierInfo[j]["azeritePowerIDs"][i]
					local azeriteSpellID = AzeriteTooltip:GetSpellID(azeritePowerID)

					local azeritePowerName, _, icon = GetSpellInfo(azeriteSpellID)
					local azeriteIcon = '|T'..icon..':20:20:0:0:64:64:4:60:4:60|t'
					local azeriteTooltipText = "  "..azeriteIcon.."  "..azeritePowerName

					if tierLevel <= currentLevel then
						if AzeriteTooltip:ScanSelectedTraits(self, azeritePowerName) then
							tinsert(activePowers, {name = azeritePowerName})
							activeAzeriteTrait = true

							addText = addText.."\n|cFF00FF00"..azeriteTooltipText.."|r"
						elseif C_AzeriteEmpoweredItem.IsPowerAvailableForSpec(azeritePowerID, specID) then
							addText = addText.."\n|cFFFFFFFF"..azeriteTooltipText.."|r"
						elseif not AzeriteTooltip.db.profile.onlyspec or IsControlKeyDown()  then
							addText = addText.."\n|cFF7a7a7a"..azeriteTooltipText.."|r"
						end
					elseif C_AzeriteEmpoweredItem.IsPowerAvailableForSpec(azeritePowerID, specID) then
						addText = addText.."\n|cFF7a7a7a"..azeriteTooltipText.."|r"
					elseif not AzeriteTooltip.db.profile.onlyspec or IsControlKeyDown() then
						addText = addText.."\n|cFF7a7a7a"..azeriteTooltipText.."|r"
					end
				end
			end
		end

		if AzeriteTooltip.db.profile.removeblizzard then
			if activeAzeriteTrait then
				for k, v in pairs(activePowers) do
					AzeriteTooltip:RemovePowerText(self, v.name)
				end
			end
			AzeriteTooltip:ClearBlizzardText(self)
		else
			self:AddLine(addText)
			self:AddLine(" ")
		end
		wipe(activePowers)
	end
end

function AzeriteTooltip:CreateAzeriteIcons(button, azeriteEmpoweredItemLocation)
	if C_AzeriteEmpoweredItem.IsAzeriteEmpoweredItem(azeriteEmpoweredItemLocation) then
	    if not button.azerite then
	        button.azerite = CreateFrame("Frame", "$parent.azerite", button);
	        button.azerite:SetPoint(AzeriteTooltip.db.profile.icon_anchor, button, AzeriteTooltip.db.profile.icon_anchor)
	        button.azerite:SetSize(37, 18)
	    else
			button.azerite:ClearAllPoints()
			button.azerite:SetPoint(AzeriteTooltip.db.profile.icon_anchor, button, AzeriteTooltip.db.profile.icon_anchor)
			button.azerite:Show()
		end

		local allTierInfo = C_AzeriteEmpoweredItem.GetAllTierInfo(azeriteEmpoweredItemLocation)
		local noneSelected = true

		for j, k in ipairs(rings) do
			if not allTierInfo[j] then break end

			local azeritePowerID = allTierInfo[k]["azeritePowerIDs"][1]

			if not allTierInfo[1]["azeritePowerIDs"][1] then return end

			for i, _ in pairs(allTierInfo[k]["azeritePowerIDs"]) do
				local azeritePowerID = allTierInfo[k]["azeritePowerIDs"][i]
				local azeriteSpellID = AzeriteTooltip:GetSpellID(azeritePowerID)
				local azeritePowerName, _, icon = GetSpellInfo(azeriteSpellID)

				if C_AzeriteEmpoweredItem.IsPowerSelected(azeriteEmpoweredItemLocation, azeritePowerID) then
					noneSelected = false
					if not button.azerite[j] then
						button.azerite[j] = button.azerite:CreateTexture("$parent."..j, "OVERLAY", nil, button.azerite)
						if j == 1 then
							button.azerite[j]:SetPoint(AzeriteTooltip.db.profile.icon_anchor, button, AzeriteTooltip.db.profile.icon_anchor)
						else
							button.azerite[j]:SetPoint("BOTTOMLEFT", button.azerite[j-1], "BOTTOMRIGHT", 4, 0)
						end
						button.azerite[j]:SetSize(16, 16)
						button.azerite[j]:SetTexture(icon)
						-- Border
				        button.azerite[j].overlay = button.azerite:CreateTexture(nil, "ARTWORK", nil, 7)
				        button.azerite[j].overlay:SetTexture([[Interface\TargetingFrame\UI-TargetingFrame-Stealable]])
				        button.azerite[j].overlay:SetVertexColor(0.7,0.7,0.7,0.8)
				        button.azerite[j].overlay:SetPoint("TOPLEFT", button.azerite[j], -3, 3)
				        button.azerite[j].overlay:SetPoint("BOTTOMRIGHT", button.azerite[j], 3, -3)
				        button.azerite[j].overlay:SetBlendMode("ADD")
					else
						if j == 1 then
							button.azerite[j]:ClearAllPoints()
							button.azerite[j]:SetPoint(AzeriteTooltip.db.profile.icon_anchor, button, AzeriteTooltip.db.profile.icon_anchor)
						end
	  					button.azerite[j]:SetTexture(icon)
					end
				end
			end
		end
		if noneSelected	then button.azerite:Hide() end
	else
		if button.azerite then
			button.azerite:Hide()
		end
	end
end

function AzeriteTooltip:SetContainerAzerite(self)
	local name = self:GetName();
    for i = 1, self.size or 1 do
        local button = self.size and _G[name .. "Item" .. i] or self;
        local self = self.size and self or button:GetParent()
        local link = GetContainerItemLink(self:GetID(), button:GetID())

	    if not button then
	        return
	    end;

		if link then
			local azeriteEmpoweredItemLocation = ItemLocation:CreateFromBagAndSlot(self:GetID(), button:GetID())

			AzeriteTooltip:CreateAzeriteIcons(button, azeriteEmpoweredItemLocation)
		else
			if button.azerite then
				button.azerite:Hide()
			end
		end
	end
end

function AzeriteTooltip:SetPaperDollAzerite(self)
    local button = self
    local id = self:GetID();
    local textureName = GetInventoryItemTexture("player", id);

    local hasItem = textureName ~= nil;

    if (id == 1 or id == 3 or id == 5) and hasItem then

	    local azeriteEmpoweredItemLocation = ItemLocation:CreateFromEquipmentSlot(id)

	    AzeriteTooltip:CreateAzeriteIcons(button, azeriteEmpoweredItemLocation)
	else
		if button.azerite then
			button.azerite:Hide()
		end
	end
end

function AzeriteTooltip:SetFlyoutAzerite(self)
	if self.azerite then
		self.azerite:Hide()
	end

	if ( not self.location ) then
		return;
	end

	if ( self.location >= EQUIPMENTFLYOUT_FIRST_SPECIAL_LOCATION ) then
		return;
	end

    local _, _, _, _, slot, bag = EquipmentManager_UnpackLocation(self.location)
    local azeriteEmpoweredItemLocation = ItemLocation:CreateFromBagAndSlot(bag, slot)
    local button = self

    if not bag then return end

    if not button then
        return
    end;

   	AzeriteTooltip:CreateAzeriteIcons(button, azeriteEmpoweredItemLocation)
end

-- HOOKS

function AzeriteTooltip:ContainerFrame_Update(frame)
	if not AzeriteTooltip.db.profile.bags then return end

	self:SetContainerAzerite(frame)
end

function AzeriteTooltip:PaperDollItemSlotButton_Update(frame)
	if not AzeriteTooltip.db.profile.paperdoll then return end

	self:SetPaperDollAzerite(frame)
end

function AzeriteTooltip:EquipmentFlyout_DisplayButton(frame)
	if not AzeriteTooltip.db.profile.paperdoll then return end

	self:SetFlyoutAzerite(frame)
end

function AzeriteTooltip:OnTooltipSetItem(frame)
	self:BuildTooltip(frame)
end

SLASH_AZERITETOOLTIP1 = "/azeritetooltip"
SLASH_AZERITETOOLTIP2 = "/at"
SlashCmdList["AZERITETOOLTIP"] = function()
    InterfaceOptionsFrame_OpenToCategory("AzeriteTooltip")
    InterfaceOptionsFrame_OpenToCategory("AzeriteTooltip")
end
