local E, L, V, P, G = unpack(ElvUI);
local LibQTip = LibStub('LibQTip-1.0')
local ACD = LibStub("AceConfigDialog-3.0")
local DT = E:GetModule('DataTexts')
local LDB = LibStub("LibDataBroker-1.1"):NewDataObject("S&L Friends",
{
	type	= "data source",
	icon	= "Interface\\Icons\\INV_Drink_08.png",
	label	= "S&L Friends",
	text	= "S&L Friends"
})
local _G = getfenv(0)
local string = _G.string
local pairs = _G.pairs
local ONE_MINUTE = 60;
local ONE_HOUR = 60 * ONE_MINUTE;
local ONE_DAY = 24 * ONE_HOUR;
local ONE_MONTH = 30 * ONE_DAY;
local ONE_YEAR = 12 * ONE_MONTH;

local realid_table = {}

local function sletime_Conversion(timeDifference, isAbsolute)
   if ( not isAbsolute ) then
      timeDifference = time() - timeDifference;
   end
   local year, month, day, hour, minute;
   
   if ( timeDifference < ONE_MINUTE ) then
      return LASTONLINE_SECS;
   elseif ( timeDifference >= ONE_MINUTE and timeDifference < ONE_HOUR ) then
      return format(LASTONLINE_MINUTES, floor(timeDifference / ONE_MINUTE));
   elseif ( timeDifference >= ONE_HOUR and timeDifference < ONE_DAY ) then
      return format(LASTONLINE_HOURS, floor(timeDifference / ONE_HOUR));
   elseif ( timeDifference >= ONE_DAY and timeDifference < ONE_MONTH ) then
      return format(LASTONLINE_DAYS, floor(timeDifference / ONE_DAY));
   elseif ( timeDifference >= ONE_MONTH and timeDifference < ONE_YEAR ) then
      return format(LASTONLINE_MONTHS, floor(timeDifference / ONE_MONTH));
   else
      return format(LASTONLINE_YEARS, floor(timeDifference / ONE_YEAR));
   end
end

local frame = CreateFrame("frame")
local tooltip
local LDB_ANCHOR
local wtcgString = BNET_CLIENT_WTCG
local GROUP_CHECKMARK	= "|TInterface\\Buttons\\UI-CheckBox-Check:0|t"
local AWAY_ICON		= "|TInterface\\FriendsFrame\\StatusIcon-Away:18|t"
local BUSY_ICON		= "|TInterface\\FriendsFrame\\StatusIcon-DnD:18|t"
local MOBILE_ICON	= "|TInterface\\ChatFrame\\UI-ChatIcon-ArmoryChat:18|t"
local MINIMIZE		= "|TInterface\\BUTTONS\\UI-PlusButton-Up:0|t"
local BROADCAST_ICON = "|TInterface\\FriendsFrame\\BroadcastIcon:0|t"

-- Setup the Title Font. 14
local ssTitleFont = CreateFont("ssTitleFont")
ssTitleFont:SetTextColor(1,0.823529,0)
ssTitleFont:SetFont(GameTooltipText:GetFont(), 14)

-- Setup the Header Font. 12
local ssHeaderFont = CreateFont("ssHeaderFont")
ssHeaderFont:SetTextColor(1,0.823529,0)
ssHeaderFont:SetFont(GameTooltipHeaderText:GetFont(), 12)

-- Setup the Regular Font. 12
local ssRegFont = CreateFont("ssRegFont")
ssRegFont:SetTextColor(1,0.823529,0)
ssRegFont:SetFont(GameTooltipText:GetFont(), 12)

local list_sort = {
	TOONNAME = function(a, b)
		return a["TOONNAME"] < b["TOONNAME"]
	end,
	LEVEL =	function(a, b)
		if a["LEVEL"] < b["LEVEL"] then
			return true
		elseif a["LEVEL"] > b["LEVEL"] then
			return false
		else  -- TOONNAME
			return a["TOONNAME"] < b["TOONNAME"]
		end
	end,
	RANKINDEX =	function(a, b)
		if a["RANKINDEX"] > b["RANKINDEX"] then
			return true
		elseif a["RANKINDEX"] < b["RANKINDEX"] then
			return false
		else -- TOONNAME
			return a["TOONNAME"] < b["TOONNAME"]
		end
	end,
	ZONENAME = function(a, b)
		if a["ZONENAME"] < b["ZONENAME"] then
			return true
		elseif a["ZONENAME"] > b["ZONENAME"] then
			return false
		else -- TOONNAME
			return a["TOONNAME"] < b["TOONNAME"]
		end
	end,
	REALMNAME = function(a, b)
		if a["REALMNAME"] < b["REALMNAME"] then
			return true
		elseif a["REALMNAME"] > b["REALMNAME"] then
			return false
		else -- TOONNAME
			return a["ZONENAME"] < b["ZONENAME"]
		end
	end,
	revTOONNAME	= function(a, b)
		return a["TOONNAME"] > b["TOONNAME"]
	end,
	revLEVEL = function(a, b)
		if a["LEVEL"] > b["LEVEL"] then
			return true
		elseif a["LEVEL"] < b["LEVEL"] then
			return false
		else  -- TOONNAME
			return a["TOONNAME"] < b["TOONNAME"]
		end
	end,
	revRANKINDEX = function(a, b)
		if a["RANKINDEX"] < b["RANKINDEX"] then
			return true
		elseif a["RANKINDEX"] > b["RANKINDEX"] then
			return false
		else -- TOONNAME
			return a["TOONNAME"] < b["TOONNAME"]
		end
	end,
	revZONENAME	= function(a, b)
		if a["ZONENAME"] > b["ZONENAME"] then
			return true
		elseif a["ZONENAME"] < b["ZONENAME"] then
			return false
		else -- TOONNAME
			return a["TOONNAME"] < b["TOONNAME"]
		end
	end,
	revREALMNAME = function(a, b)
		if a["REALMNAME"] > b["REALMNAME"] then
			return true
		elseif a["REALMNAME"] < b["REALMNAME"] then
			return false
		else -- TOONNAME
			return a["ZONENAME"] < b["ZONENAME"]
		end
	end
}

local function inGroup(name)
	if GetNumSubgroupMembers() > 0 and UnitInParty(name) then
		return true
	elseif GetNumGroupMembers() > 0 and UnitInRaid(name) then
		return true
	end

	return false
end

local function nameIndex(name)
	local lookupname

	for i = 1, GetNumFriends() do
		lookupname = GetFriendInfo(i)
		if lookupname == name then
			return i
		end
	end
end

local function ColoredLevel(level)
	if level ~= "" then
		local color = GetQuestDifficultyColor(level)
		return string.format("|cff%02x%02x%02x%d|r", color.r * 255, color.g * 255, color.b * 255, level)
	end
end

local CLASS_COLORS, color = {}
local classes_female, classes_male = {}, {}

FillLocalizedClassList(classes_female, true)
FillLocalizedClassList(classes_male, false)

for token, localizedName in pairs(classes_female) do
	color = RAID_CLASS_COLORS[token]
	CLASS_COLORS[localizedName] = string.format("%02x%02x%02x", color.r * 255, color.g * 255, color.b * 255) 
end

for token, localizedName in pairs(classes_male) do
	color = RAID_CLASS_COLORS[token]
	CLASS_COLORS[localizedName] = string.format("%02x%02x%02x", color.r * 255, color.g * 255, color.b * 255) 
end

local function valueColor(totals)
	if totals ~= "" then
		local color = E.db.general.valuecolor
		return string.format("|cff%02x%02x%02x%d|r", color.r * 255, color.g * 255, color.b * 255, totals)
	end
end

function DT:update_Friends()
	ShowFriends()
	local friendsTotal, friendsOnline = GetNumFriends()
	local bnTotal, bnOnline = BNGetNumFriends()
	local totalOnline = friendsOnline + bnOnline
	local totalFriends = friendsTotal + bnTotal

	if E.db.sle.dt.friends.totals then
		LDB.text = "|cffffffff"..L['Friends']..": |r"..valueColor(totalOnline).."/"..valueColor(totalFriends)
	else
		LDB.text = "|cffffffff"..L['Friends']..": |r"..valueColor(totalOnline)
	end
end

local function Entry_OnMouseUp(frame, info, button)
	local i_type, toon_name, full_name, presence_id = string.split(":", info)

	if button == "LeftButton" then
		if IsAltKeyDown() then
			if i_type == "realid" then
				local presenceID, presenceName, battleTag, isBattleTagPresence, toonName, toonID = BNGetFriendInfo(BNGetFriendIndex(presence_id))
				local _, toonName, client, realmName, realmID, faction, race, class, guild, zoneName, level, gameText = BNGetToonInfo(toonID or 0)

				InviteUnit(toon_name.."-"..realmName)
				return
			else
				InviteUnit(toon_name)
				return
			end
		end

		if IsShiftKeyDown() then
			SetItemRef("player:"..toon_name, "|Hplayer:"..toon_name.."|h["..toon_name.."|h", "LeftButton")
			return
		end

		if IsControlKeyDown() then
			if i_type == "friends" then
				FriendsFrame.NotesID = nameIndex(toon_name)
 				StaticPopup_Show("SET_FRIENDNOTE", GetFriendInfo(FriendsFrame.NotesID))
 				return
			end

			if i_type == "realid" then
				FriendsFrame.NotesID = presence_id
				StaticPopup_Show("SET_BNFRIENDNOTE", full_name)
				return
			end
		end

		if i_type == "realid" then
			local name
			for _, player in ipairs(realid_table) do
				if player["GIVENNAME"] == presence_id and player["CLIENT"] == "Hero" then
					name = presence_id..":"..player["PRESENCEID"]
					break
				end
			end
			if not name then name = full_name..":"..presence_id end
			SetItemRef( "BNplayer:"..name, ("|HBNplayer:%1$s|h[%1$s]|h"):format(name), "LeftButton" )     
		else
			SetItemRef( "player:"..full_name, ("|Hplayer:%1$s|h[%1$s]|h"):format(full_name), "LeftButton" )
		end
	elseif button == "RightButton" then
		if IsControlKeyDown() then
			--Possibly Set BNetBroadcast
			--	E:StaticPopup_Show("SET_BN_BROADCAST")
		end
	elseif button == "MiddleButton" then
		E.db.sle.dt.friends.expandBNBroadcast = not E.db.sle.dt.friends.expandBNBroadcast
		LDB.OnEnter(LDB_ANCHOR)
	end
end

local function HideOnMouseUp(cell, section)
	E.db.sle.dt.friends[section] = not E.db.sle.dt.friends[section]
	LDB.OnEnter(LDB_ANCHOR)
end

local function SetRealIDSort(cell, sortsection)
	if E.db.sle.dt.friends["sortBN"] == sortsection then
		E.db.sle.dt.friends["sortBN"] = "rev" .. sortsection
	else
		E.db.sle.dt.friends["sortBN"] = sortsection
	end
	LDB.OnEnter(LDB_ANCHOR)
end

function LDB:OnClick(button)
	if button == "LeftButton" then
		ToggleFriendsFrame()
	end

	if button == "RightButton" then
		ElvConfigToggle:Click();
		ACD:SelectGroup("ElvUI", "sle", "sldatatext", "slfriends")
	end
end

function LDB.OnLeave() end

function LDB.OnEnter(self)
	if SLE_SS:IsShown() then return end
	if E.db.sle.dt.friends.combat and InCombatLockdown() then return end
	LDB_ANCHOR = self

	if LibQTip:IsAcquired("ShadowLightFriends") then
		tooltip:Clear()
	else
		tooltip = LibQTip:Acquire("ShadowLightFriends", 8, "RIGHT", "RIGHT", "LEFT", "LEFT", "CENTER", "CENTER", "RIGHT")

		tooltip:SetBackdropColor(0,0,0,1)

		tooltip:SetHeaderFont(ssHeaderFont)
		tooltip:SetFont(ssRegFont)

		tooltip:SmartAnchorTo(self)
		tooltip:SetAutoHideDelay(E.db.sle.dt.friends.tooltipAutohide, self)
		tooltip:SetScript("OnShow", function(ttskinself) ttskinself:SetTemplate('Transparent') end)
	end

	local line = tooltip:AddLine()
	tooltip:SetCell(line, 1, "Shadow & Light Friends", ssTitleFont, "CENTER", 0)
	tooltip:AddLine(" ")

	local _, numBNOnline = BNGetNumFriends()
	local _, numFriendsOnline = GetNumFriends()

	if (numBNOnline > 0) or (numFriendsOnline > 0) then
		line = tooltip:AddLine()
		if not E.db.sle.dt.friends.hideFriends then
			tooltip:SetCell(line, 1, "|cffffffff" .. _G.FRIENDS .. "|r", "LEFT", 3)
		else
			tooltip:SetCell(line, 1, "|cffffffff" .. MINIMIZE .. _G.FRIENDS .. "|r", "LEFT", 3)
		end
		tooltip:SetCellScript(line, 1, "OnMouseUp", HideOnMouseUp, "hideFriends")

		if not E.db.sle.dt.friends.hideFriends then
			line = tooltip:AddHeader()
			line = tooltip:SetCell(line, 1, "  ")
			tooltip:SetCellScript(line, 1, "OnMouseUp", SetRealIDSort, "LEVEL")
			line = tooltip:SetCell(line, 3, _G.NAME)
			tooltip:SetCellScript(line, 3, "OnMouseUp", SetRealIDSort, "TOONNAME")
			line = tooltip:SetCell(line, 4, _G.BATTLENET_FRIEND)
			tooltip:SetCellScript(line, 4, "OnMouseUp", SetRealIDSort, "REALID")
			line = tooltip:SetCell(line, 5, _G.LOCATION_COLON)
			tooltip:SetCellScript(line, 5, "OnMouseUp", SetRealIDSort, "ZONENAME")
			line = tooltip:SetCell(line, 6, _G.FRIENDS_LIST_REALM)
			tooltip:SetCellScript(line, 6, "OnMouseUp", SetRealIDSort, "REALMNAME")
			if not E.db.sle.dt.friends.hideFriendsNotes then
				line = tooltip:SetCell(line, 7, _G.NOTE_COLON)
			else
				line = tooltip:SetCell(line, 7, MINIMIZE .. _G.NOTE_COLON)
			end
			tooltip:SetCellScript(line, 7, "OnMouseUp", HideOnMouseUp, "hideFriendsNotes")

			tooltip:AddSeparator()

			if numBNOnline > 0 then
				wipe(realid_table)
				for i = 1, numBNOnline do
					local presenceID, givenName, bTag, _, _, toonID, gameClient, isOnline, lastOnline, isAFK, isDND, broadcast, note, _, castTime = BNGetFriendInfo(i)
					local _, toonName, client, realmName, realmID, faction, race, class, guild, zoneName, level, gameText = BNGetToonInfo(toonID or 0)
					local broadcastTime = ""
					if castTime then
						broadcastTime = string.format(BNET_BROADCAST_SENT_TIME, sletime_Conversion(castTime));
					end
					
					local fcolor
					local status = ""
					if toonName then
						if faction then
							if faction == "Horde" then
								fcolor = RED_FONT_COLOR_CODE
							else
								fcolor = "|cff0070dd"
							end
						end
						if isAFK then
							status = AWAY_ICON
						end
						if isDND then
							status = BUSY_ICON
						end
						if note and note ~= "" then note = "|cffff8800{"..note.."}|r" end
							
						table.insert(realid_table, {
							GIVENNAME = givenName,
							SURNAME = bTag or "",
							LEVEL = level,
							CLASS = class,
							FCOLOR = fcolor,
							STATUS = status,
							BROADCAST_TEXT = broadcast or "",
							BROADCAST_TIME = broadcastTime or "",
							TOONNAME = toonName,
							CLIENT = client,
							ZONENAME = zoneName,
							REALMNAME = realmName,
							GAMETEXT = gameText,
							NOTE = note,
							PRESENCEID = presenceID
							})
					end
				end

				if (E.db.sle.dt.friends["sortBN"] ~= "REALID") and (E.db.sle.dt.friends["sortBN"] ~= "revREALID") then
					table.sort(realid_table, list_sort[E.db.sle.dt.friends["sortBN"]])
				end

				for _, player in ipairs(realid_table) do
					local broadcast_flag
					if not E.db.sle.dt.friends.expandBNBroadcast and player["BROADCAST_TEXT"] ~= "" then
						broadcast_flag = " " .. BROADCAST_ICON
					else
						broadcast_flag = ""
					end

					line = tooltip:AddLine()
					line = tooltip:SetCell(line, 1, ColoredLevel(player["LEVEL"]))
					line = tooltip:SetCell(line, 2, player["STATUS"])
					if player["CLIENT"] ~= "Hero" then
						line = tooltip:SetCell(line, 3,
						string.format("|cff%s%s",CLASS_COLORS[player["CLASS"]] or "B8B8B8", player["TOONNAME"] .. "|r")..
						(inGroup(player["TOONNAME"]) and GROUP_CHECKMARK or ""))
					else
						line = tooltip:SetCell(line, 3, string.format(""))
					end
					line = tooltip:SetCell(line, 4,
						"|cff82c5ff" .. player["GIVENNAME"] .. "|r" .. broadcast_flag)

					if player["CLIENT"] == "WoW" then
						line = tooltip:SetCell(line, 5, player["ZONENAME"])
						line = tooltip:SetCell(line, 6, player["FCOLOR"] .. player["REALMNAME"] .. "|r")
					elseif player["CLIENT"] == "App" then
							line = tooltip:SetCell(line, 5, "|cff82c5ffDesktop Application|r")
							line = tooltip:SetCell(line, 6, "|cff01b2f1Battle.net|r")
					else
						line = tooltip:SetCell(line, 5, player["GAMETEXT"])
						if player["CLIENT"] == "S2" then
							line = tooltip:SetCell(line, 6, "|cff82c5ffStarCraft 2|r")
						end

						if player["CLIENT"] == "D3" then
							line = tooltip:SetCell(line, 6, "|cffad835aDiablo 3|r")
						end
						
						if player["CLIENT"] == wtcgString then
							line = tooltip:SetCell(line, 6, "|cff82c5ffHearthstone|r")
						end
						if player["CLIENT"] == "Hero" then
							line = tooltip:SetCell(line, 6, "|cff82c5ffHeroes of The Storm|r")
						end
					end

					if not E.db.sle.dt.friends.hideFriendsNotes then
						line = tooltip:SetCell(line, 7, player["NOTE"])
					end

					tooltip:SetLineScript(line, "OnMouseUp", Entry_OnMouseUp, string.format("realid:%s:%s:%d", player["TOONNAME"], player["GIVENNAME"], player["PRESENCEID"]))

					if E.db.sle.dt.friends.expandBNBroadcast and player["BROADCAST_TEXT"] ~= "" then
						line = tooltip:AddLine()
						line = tooltip:SetCell(line, 1, BROADCAST_ICON .. " |cff7b8489" .. player["BROADCAST_TEXT"] .. "|r "..player["BROADCAST_TIME"], "LEFT", 0)
						tooltip:SetLineScript(line, "OnMouseUp", Entry_OnMouseUp, string.format("realid:%s:%s:%d", player["TOONNAME"], player["GIVENNAME"], player["PRESENCEID"]))
					end
				end
				tooltip:AddLine(" ")
			end

			if numFriendsOnline > 0 then
				local friend_table = {}
				for i = 1,numFriendsOnline do
					local toonName, level, class, zoneName, connected, status, note = GetFriendInfo(i)
					note = note and "|cffff8800{"..note.."}|r" or ""

					if status == CHAT_FLAG_AFK then
						status = AWAY_ICON
					elseif status == CHAT_FLAG_DND then
						status = BUSY_ICON
					end

					table.insert(friend_table, {
						TOONNAME = toonName,
						LEVEL = level,
						CLASS = class,
						ZONENAME = zoneName,
						REALMNAME = "",
						STATUS = status,
						NOTE = note
						})
				end

				if (E.db.sle.dt.friends["sortBN"] ~= "REALID") and (E.db.sle.dt.friends["sortBN"] ~= "revREALID") then
					table.sort(friend_table, list_sort[E.db.sle.dt.friends["sortBN"]])
				else
					table.sort(friend_table, list_sort["TOONNAME"])
				end

				for _, player in ipairs(friend_table) do
					line = tooltip:AddLine()
					line = tooltip:SetCell(line, 1, ColoredLevel(player["LEVEL"]))
					line = tooltip:SetCell(line, 2, player["STATUS"])
					line = tooltip:SetCell(line, 3,
						string.format("|cff%s%s", CLASS_COLORS[player["CLASS"]] or "ffffff", player["TOONNAME"] .. "|r") .. (inGroup(player["TOONNAME"]) and GROUP_CHECKMARK or ""));
					line = tooltip:SetCell(line, 5, player["ZONENAME"])
					if not E.db.sle.dt.friends.hideFriendsNotes then
						line = tooltip:SetCell(line, 7, player["NOTE"])
					end
					tooltip:SetLineScript(line, "OnMouseUp", Entry_OnMouseUp, string.format("friends:%s:%s", player["TOONNAME"], player["TOONNAME"]))
				end
			end
		end
		tooltip:AddLine(" ")
	end

	if not E.db.sle.dt.friends.hide_hintline then
		line = tooltip:AddLine()
		if not E.db.sle.dt.friends.minimize_hintline then
			tooltip:SetCell(line, 1, "Hint:", "LEFT", 3)
		else
			tooltip:SetCell(line, 1, MINIMIZE .. "Hint:", "LEFT", 3)
		end
		tooltip:SetCellScript(line, 1, "OnMouseUp", HideOnMouseUp, "minimize_hintline")

		if not E.db.sle.dt.friends.minimize_hintline then
			line = tooltip:AddLine()
			tooltip:SetCell(line, 1, "", "LEFT", 1)
			tooltip:SetCell(line, 2, "|cffeda55fLeft Click|r to open the friends panel.", "LEFT", 3)
			tooltip:SetCell(line, 5, "|cffeda55fRight Click|r to open configuration panel.", "LEFT", 3)
			line = tooltip:AddLine()
			tooltip:SetCell(line, 1, "", "LEFT", 1)
			tooltip:SetCell(line, 2, "|cffeda55fLeft Click|r a line to whisper a player.", "LEFT", 3)
			tooltip:SetCell(line, 5, "|cffeda55fShift+Left Click|r a line to lookup a player.", "LEFT", 3)
			line = tooltip:AddLine()
			tooltip:SetCell(line, 1, "", "LEFT", 1)
			tooltip:SetCell(line, 2, "|cffeda55fCtrl+Left Click|r a line to edit a note.", "LEFT", 3)
			tooltip:SetCell(line, 5, "|cffeda55fMiddleClick|r a line to expand RealID.", "LEFT", 3)
			line = tooltip:AddLine()
			tooltip:SetCell(line, 1, "", "LEFT", 1)
			tooltip:SetCell(line, 2, "|cffeda55fAlt+Left Click|r a line to invite.", "LEFT", 3)
			tooltip:SetCell(line, 5, "|cffeda55fLeft Click|r a Header to hide it or sort it.", "LEFT", 3)
		end
	end

	tooltip:UpdateScrolling()
	tooltip:Show()
end

frame:SetScript("OnEvent", function(self, event, ...)
	if self[event] then
		return self[event](self, event, ...) 
	end 
end)

local DELAY = 15  --  Update every 15 seconds
local elapsed = DELAY - 5

frame:SetScript("OnUpdate", function (self, elapse)
	elapsed = elapsed + elapse

	if elapsed >= DELAY then
		elapsed = 0
		DT:update_Friends()
	end
end)

frame:RegisterEvent("PLAYER_LOGIN")