local E, L, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local M = E:GetModule("Misc");

--Cache global variables
--Lua functions
local find, match = string.find, string.match
local pairs, unpack, ipairs, next, tonumber = pairs, unpack, ipairs, next, tonumber
local tinsert = table.insert
--WoW API / Variables
local CursorOnUpdate = CursorOnUpdate
local DressUpItemLink = DressUpItemLink
local GetLootRollItemInfo = GetLootRollItemInfo
local GetLootRollItemLink = GetLootRollItemLink
local GetLootRollTimeLeft = GetLootRollTimeLeft
local IsControlKeyDown = IsControlKeyDown
local IsShiftKeyDown = IsShiftKeyDown
local ResetCursor = ResetCursor
local RollOnLoot = RollOnLoot
local ShowInspectCursor = ShowInspectCursor
local CUSTOM_CLASS_COLORS = CUSTOM_CLASS_COLORS
local ITEM_QUALITY_COLORS = ITEM_QUALITY_COLORS
local RAID_CLASS_COLORS = RAID_CLASS_COLORS

local pos = "TOP"
local cancelled_rolls = {}
local FRAME_WIDTH, FRAME_HEIGHT = 328, 28
M.RollBars = {}

local locale = GetLocale()
local rollpairs = locale == "deDE" and {
	["(.*) würfelt nicht für: (.+|r)$"] = "pass",
	["(.*) hat für (.+) 'Gier' ausgewählt"] = "greed",
	["(.*) hat für (.+) 'Bedarf' ausgewählt"] = "need",
} or locale == "frFR" and {
	["(.*) a passé pour : (.+)"] = "pass",
	["(.*) a choisi Cupidité pour : (.+)"] = "greed",
	["(.*) a choisi Besoin pour : (.+)"] = "need",
} or locale == "zhTW" and {
	["(.*)放棄了:(.+)"] = "pass",
	["(.*)選擇了貪婪:(.+)"] = "greed",
	["(.*)選擇了需求:(.+)"] = "need",
} or locale == "ruRU" and {
	["(.*) отказывается от предмета (.+)%."] = "pass",
	["Разыгрывается: (.+)%. (.*): \"Не откажусь\""] = "greed",
	["Разыгрывается: (.+)%. (.*): \"Мне это нужно\""] = "need",
} or locale == "koKR" and {
	["(.*)님이 주사위 굴리기를 포기했습니다: (.+)"] = "pass",
	["(.*)님이 차비를 선택했습니다: (.+)"] = "greed",
	["(.*)님이 입찰을 선택했습니다: (.+)"] = "need",
} or locale == "esES" and {
	["^(.*) pasó de: (.+|r)$"] = "pass",
	["(.*) eligió Codicia para: (.+)"] = "greed",
	["(.*) eligió Necesidad para: (.+)"] = "need",
} or locale == "esMX" and {
	["^(.*) pasó de: (.+|r)$"] = "pass",
	["(.*) eligió Codicia para: (.+)"] = "greed",
	["(.*) eligió Necesidad para: (.+)"] = "need",
} or {
	["^(.*) passed on: (.+|r)$"] = "pass",
	["(.*) has selected Greed for: (.+)"] = "greed",
	["(.*) has selected Need for: (.+)"] = "need",
}

local function ClickRoll(frame)
	RollOnLoot(frame.parent.rollID, frame.rolltype)
end

local function HideTip() GameTooltip:Hide() end
local function HideTip2() GameTooltip:Hide() ResetCursor() end

local rolltypes = {"need", "greed", [0] = "pass"}
local function SetTip(frame)
	GameTooltip:SetOwner(frame, "ANCHOR_RIGHT")
	GameTooltip:SetText(frame.tiptext)
	if frame:IsEnabled() == 0 then
		GameTooltip:AddLine("|cffff3333"..L["Can't Roll"])
	end

	for name, tbl in pairs(frame.parent.rolls) do
		if tbl[1] == rolltypes[frame.rolltype] and tbl[2] then
			local classColor = CUSTOM_CLASS_COLORS and CUSTOM_CLASS_COLORS[tbl[2]] or RAID_CLASS_COLORS[tbl[2]]
			GameTooltip:AddLine(name, classColor.r, classColor.g, classColor.b)
		end
	end
	GameTooltip:Show()
end

local function SetItemTip(frame)
	if not frame.link then return end

	GameTooltip:SetOwner(frame, "ANCHOR_TOPLEFT")
	GameTooltip:SetHyperlink(match(frame.link, "item[%-?%d:]+"))
	-- if IsShiftKeyDown() then
	-- 	GameTooltip_ShowCompareItem()
	-- end
	if IsControlKeyDown() then
		ShowInspectCursor()
	else
		ResetCursor()
	end
end

local function ItemOnUpdate(self)
	-- if IsShiftKeyDown() then
	-- 	GameTooltip_ShowCompareItem()
	-- end
	CursorOnUpdate(self)
end

local function LootClick(frame)
	if IsControlKeyDown() then
		DressUpItemLink(frame.link)
	elseif IsShiftKeyDown() then
		ChatEdit_InsertLink(frame.link)
	end
end

local function OnEvent(frame)
	local rollID = arg1
	cancelled_rolls[rollID] = true
	if frame.rollID ~= rollID then return end

	frame.rollID = nil
	frame.time = nil
	frame:Hide()
end

local function StatusUpdate(frame)
	if not frame.parent.rollID then return end
	local t = GetLootRollTimeLeft(frame.parent.rollID)
	local perc = t / frame.parent.time
	E:Point(frame.spark, "CENTER", frame, "LEFT", perc * frame:GetWidth(), 0)
	frame:SetValue(t)

	if t > 1000000000 then
		frame:GetParent():Hide()
	end
end

local function CreateRollButton(parent, ntex, ptex, htex, rolltype, tiptext, point, relativeFrame, relativePoint, ofsx, ofsy)
	local f = CreateFrame("Button", nil, parent)
	E:Point(f, point, relativeFrame, relativePoint, ofsx, ofsy)
	E:Size(f, FRAME_HEIGHT - 4)
	f:SetNormalTexture(ntex)
	if ptex then f:SetPushedTexture(ptex) end
	f:SetHighlightTexture(htex)
	f.rolltype = rolltype
	f.parent = parent
	f.tiptext = tiptext
	f:SetScript("OnEnter", function() SetTip(f) end)
	f:SetScript("OnLeave", HideTip)
	f:SetScript("OnClick", function() ClickRoll(f) end)
	local txt = f:CreateFontString(nil, nil)
	E:FontTemplate(txt, nil, nil, "OUTLINE")
	E:Point(txt, "CENTER", 0, rolltype == 2 and 1 or rolltype == 0 and -1.2 or 0)
	return f, txt
end

function M:CreateRollFrame()
	local frame = CreateFrame("Frame", nil, E.UIParent)
	E:Size(frame, FRAME_WIDTH, FRAME_HEIGHT)
	E:SetTemplate(frame, "Default")
	frame:SetScript("OnEvent", function() OnEvent(frame) end)
	frame:RegisterEvent("CANCEL_LOOT_ROLL")
	frame:Hide()

	local button = CreateFrame("Button", nil, frame)
	E:Point(button, "RIGHT", frame, "LEFT", -(E.Spacing*3), 0)
	E:Size(button, FRAME_HEIGHT - (E.Border * 2))
	E:CreateBackdrop(button, "Default")
	button:SetScript("OnEnter", function() SetItemTip(button) end)
	button:SetScript("OnLeave", HideTip2)
	button:SetScript("OnUpdate", function() ItemOnUpdate(button) end)
	button:SetScript("OnClick", function() LootClick(button) end)
	frame.button = button

	button.icon = button:CreateTexture(nil, "OVERLAY")
	button.icon:SetAllPoints()
	button.icon:SetTexCoord(unpack(E.TexCoords))

	local tfade = frame:CreateTexture(nil, "BORDER")
	E:Point(tfade, "TOPLEFT", frame, "TOPLEFT", 4, 0)
	E:Point(tfade, "BOTTOMRIGHT", frame, "BOTTOMRIGHT", -4, 0)
	tfade:SetTexture("Interface\\ChatFrame\\ChatFrameBackground")
	tfade:SetBlendMode("ADD")
	tfade:SetGradientAlpha("VERTICAL", .1, .1, .1, 0, .1, .1, .1, 0)

	local status = CreateFrame("StatusBar", nil, frame)
	E:SetInside(status)
	status:SetScript("OnUpdate", function() StatusUpdate(status) end)
	status:SetFrameLevel(status:GetFrameLevel() - 1)
	status:SetStatusBarTexture(E.media.normTex)
	E:RegisterStatusBar(status)
	status:SetStatusBarColor(.8, .8, .8, .9)
	status.parent = frame
	frame.status = status

	status.bg = status:CreateTexture(nil, "BACKGROUND")
	status.bg:SetAlpha(0.1)
	status.bg:SetAllPoints()
	local spark = frame:CreateTexture(nil, "OVERLAY")
	E:Size(spark, 14, FRAME_HEIGHT)
	spark:SetTexture("Interface\\CastingBar\\UI-CastingBar-Spark")
	spark:SetBlendMode("ADD")
	status.spark = spark

	local need, needtext = CreateRollButton(frame, "Interface\\Buttons\\UI-GroupLoot-Dice-Up", "Interface\\Buttons\\UI-GroupLoot-Dice-Highlight", "Interface\\Buttons\\UI-GroupLoot-Dice-Down", 1, NEED, "LEFT", frame.button, "RIGHT", 5, -1)
	local greed, greedtext = CreateRollButton(frame, "Interface\\Buttons\\UI-GroupLoot-Coin-Up", "Interface\\Buttons\\UI-GroupLoot-Coin-Highlight", "Interface\\Buttons\\UI-GroupLoot-Coin-Down", 2, GREED, "LEFT", need, "RIGHT", 0, -1)
	local pass, passtext = CreateRollButton(frame, "Interface\\AddOns\\ElvUI\\media\\textures\\UI-GroupLoot-Pass-Up", nil, "Interface\\AddOns\\ElvUI\\media\\textures\\UI-GroupLoot-Pass-Down", 0, PASS, "LEFT", greed, "RIGHT", 0, 2)
	frame.needbutt, frame.greedbutt = need, greed
	frame.need, frame.greed, frame.pass = needtext, greedtext, passtext

	local bind = frame:CreateFontString()
	E:Point(bind, "LEFT", pass, "RIGHT", 3, 1)
	E:FontTemplate(bind, nil, nil, "OUTLINE")
	frame.fsbind = bind

	local loot = frame:CreateFontString(nil, "ARTWORK")
	E:FontTemplate(loot, nil, nil, "OUTLINE")
	E:Point(loot, "LEFT", bind, "RIGHT", 0, 0)
	E:Point(loot, "RIGHT", frame, "RIGHT", -5, 0)
	E:Size(loot, 200, 10)
	loot:SetJustifyH("LEFT")
	frame.fsloot = loot

	frame.rolls = {}

	return frame
end

local function GetFrame()
	for _, f in ipairs(M.RollBars) do
		if not f.rollID then
			return f
		end
	end

	local f = M:CreateRollFrame()
	if pos == "TOP" then
		E:Point(f, "TOP", next(M.RollBars) and M.RollBars[getn(M.RollBars)] or AlertFrameHolder, "BOTTOM", 0, -4)
	else
		E:Point(f, "BOTTOM", next(M.RollBars) and M.RollBars[getn(M.RollBars)] or AlertFrameHolder, "TOP", 0, 4)
	end

	tinsert(M.RollBars, f)

	return f
end

function M:START_LOOT_ROLL()
	if cancelled_rolls[rollID] then return end

	local f = GetFrame()
	f.rollID = arg1
	f.time = arg2
	for i in pairs(f.rolls) do f.rolls[i] = nil end
	f.need:SetText(0)
	f.greed:SetText(0)
	f.pass:SetText(0)

	local texture, name, _, quality, bindOnPickUp = GetLootRollItemInfo(arg1)
	f.button.icon:SetTexture(texture)
	f.button.link = GetLootRollItemLink(arg1)

	f.needbutt:Enable()
	f.greedbutt:Enable()
	SetDesaturation(f.needbutt:GetNormalTexture())
	SetDesaturation(f.greedbutt:GetNormalTexture())
	f.needbutt:SetAlpha(1)
	f.greedbutt:SetAlpha(1)

	f.fsbind:SetText(bindOnPickUp and "BoP" or "BoE")
	f.fsbind:SetVertexColor(bindOnPickUp and 1 or .3, bindOnPickUp and .3 or 1, bindOnPickUp and .1 or .3)

	local color = ITEM_QUALITY_COLORS[quality]
	f.fsloot:SetText(name)
	f.status:SetStatusBarColor(color.r, color.g, color.b, .7)
	f.status.bg:SetTexture(color.r, color.g, color.b)

	f.status:SetMinMaxValues(0, arg2)
	f.status:SetValue(arg2)

	E:Point(f, "CENTER", WorldFrame, "CENTER")
	f:Show()

	if E.db.general.autoRoll and UnitLevel("player") == MAX_PLAYER_LEVEL and quality == 2 and not bindOnPickUp then
		RollOnLoot(arg1, 2)
	end
end

function M:ParseRollChoice(msg)
	if not msg then return end
	for i, v in pairs(rollpairs) do
		local _, _, playername, itemname = find(msg, i)
		if locale == "ruRU" and (v == "greed" or v == "need") then
			local temp = playername
			playername = itemname
			itemname = temp
		end
		if playername and itemname and playername ~= "Everyone" then return playername, itemname, v end
	end
end

function M:CHAT_MSG_LOOT()
	local playername, itemname, rolltype = self:ParseRollChoice(arg1)
	if playername and itemname and rolltype then
		for _, f in ipairs(M.RollBars) do
			if f.rollID and f.button.link == itemname and not f.rolls[playername] then
				f.rolls[playername] = { rolltype }
				f[rolltype]:SetText(tonumber(f[rolltype]:GetText()) + 1)
				return
			end
		end
--[[
		local _, class = UnitClass(playername)
		for _, f in ipairs(M.RollBars) do
			if f.rollID and f.button.link == itemname and not f.rolls[playername] then
				f.rolls[playername] = { rolltype, class }
				f[rolltype]:SetText(tonumber(f[rolltype]:GetText()) + 1)
				return
			end
		end
]]
	end

end

function M:LoadLootRoll()
	if not E.private.general.lootRoll then return end

	self:RegisterEvent("START_LOOT_ROLL")
	self:RegisterEvent("CHAT_MSG_LOOT")
	UIParent:UnregisterEvent("START_LOOT_ROLL")
	UIParent:UnregisterEvent("CANCEL_LOOT_ROLL")
end