local PA = _G.ProjectAzilroka
local BrokerLDB = PA:NewModule('BrokerLDB', 'AceEvent-3.0')
PA.BrokerLDB, _G.BrokerLDB = BrokerLDB, BrokerLDB

local _G = _G
local pairs = pairs
local tinsert = tinsert
local tremove = tremove

BrokerLDB.Title = 'BrokerLDB'
BrokerLDB.Header = PA.ACL['|cFF16C3F2Broker|r|cFFFFFFFFLDB|r']
BrokerLDB.Description = PA.ACL['Provides a Custom DataBroker Bar']
BrokerLDB.Authors = 'Azilroka'
BrokerLDB.isEnabled = false

function BrokerLDB:TextUpdate(_, Name, _, Data)
	BrokerLDB.PluginObjects[Name]:SetText(Data)
end

function BrokerLDB:ValueUpdate(_, Name, _, Data, Object)
	BrokerLDB.PluginObjects[Name]:SetFormattedText('%s %s', Data, Object.suffix)
end

function BrokerLDB:AnimateSlide(frame, x, y, duration)
	frame.anim = frame:CreateAnimationGroup('Move_In')
	frame.anim.in1 = frame.anim:CreateAnimation('Translation')
	frame.anim.in1:SetDuration(0)
	frame.anim.in1:SetOrder(1)
	frame.anim.in2 = frame.anim:CreateAnimation('Translation')
	frame.anim.in2:SetDuration(duration)
	frame.anim.in2:SetOrder(2)
	frame.anim.in2:SetSmoothing('OUT')
	frame.anim.out1 = frame:CreateAnimationGroup('Move_Out')
	frame.anim.out2 = frame.anim.out1:CreateAnimation('Translation')
	frame.anim.out2:SetDuration(duration)
	frame.anim.out2:SetOrder(1)
	frame.anim.out2:SetSmoothing('IN')
	frame.anim.in1:SetOffset(x, y)
	frame.anim.in2:SetOffset(-x, -y)
	frame.anim.out2:SetOffset(x, y)
	frame.anim.out1:SetScript('OnFinished', function() frame:Hide() end)
end

function BrokerLDB:AnimSlideIn(frame)
	frame.anim.out1:Stop()
	frame:Show()
	frame.anim:Play()
end

function BrokerLDB:AnimSlideOut(frame)
	frame.anim:Finish()
	frame.anim:Stop()
	frame.anim.out1:Play()
end

function BrokerLDB:SlideOut()
	for _, Slides in pairs(BrokerLDB.Whitelist) do
		BrokerLDB:AnimSlideIn(Slides)
	end
	BrokerLDB:AnimSlideIn(BrokerLDB.Frame)
	BrokerLDB.Frame.Arrow:SetRotation(1.57)
	BrokerLDB.Slide = 'Out'
end

function BrokerLDB:SlideIn()
	for _, Slides in pairs(BrokerLDB.Buttons) do
		Slides:Hide()
	end
	BrokerLDB.Frame.Arrow:SetRotation(-1.57)
	BrokerLDB.Slide = 'In'
end

function BrokerLDB:Update()
	for Name, Object in PA.LDB:DataObjectIterator() do
		BrokerLDB:New(nil, Name, Object)
	end

	for Key, Slide in pairs(BrokerLDB.Buttons) do
		Slide.Text:SetFont(PA.LSM:Fetch('font', BrokerLDB.db['Font']), BrokerLDB.db['FontSize'], BrokerLDB.db['FontFlag'])
		if BrokerLDB.db['ShowIcon'] and BrokerLDB.db['ShowText'] then
			if BrokerLDB.db['PanelWidth'] == 0 then BrokerLDB.db['PanelWidth'] = 140 end
			Slide:SetSize(BrokerLDB.db['PanelWidth'] + BrokerLDB.db['PanelHeight'], BrokerLDB.db['PanelHeight'])
			Slide.IconBackdrop:Show()
			Slide.IconBackdrop:SetPoint('RIGHT', Slide, 'RIGHT', -2, 0)
			Slide.IconBackdrop:Size(BrokerLDB.db['PanelHeight'] - 4)
			Slide.Text:Show()
			Slide.Text:SetPoint('CENTER', -(BrokerLDB.db['PanelHeight'] / 2), 0)
		elseif BrokerLDB.db['ShowIcon'] then
			BrokerLDB.db['PanelWidth'] = 0
			Slide:SetSize(BrokerLDB.db['PanelHeight'], BrokerLDB.db['PanelHeight'])
			Slide.IconBackdrop:Show()
			Slide.IconBackdrop:Size(BrokerLDB.db['PanelHeight'])
			Slide.IconBackdrop:SetPoint('RIGHT', Slide, 'RIGHT', 0, 0)
			Slide.Text:Hide()
		elseif BrokerLDB.db['ShowText'] then
			if BrokerLDB.db['PanelWidth'] == 0 then BrokerLDB.db['PanelWidth'] = 140 end
			Slide:SetSize(BrokerLDB.db['PanelWidth'], BrokerLDB.db['PanelHeight'])
			Slide.IconBackdrop:Hide()
			Slide.Text:Show()
			Slide.Text:SetPoint('CENTER', 0, 0)
		end
		if Slide.anim then
			local x = BrokerLDB.db["PanelWidth"] + BrokerLDB.db["PanelHeight"]
			Slide.anim.in1:SetOffset(-x, 0)
			Slide.anim.in2:SetOffset(x, 0)
			Slide.anim.out2:SetOffset(-x, 0)
		end
		for _, Blacklisted in pairs(BrokerLDB.Blacklist) do
			if Slide:GetName() == Blacklisted then tremove(BrokerLDB.Whitelist, Key) Slide.Enabled = false return end
		end
	end

	local yOffSet = 0
	for _, Slide in pairs(BrokerLDB.Whitelist) do
		Slide:SetPoint('TOPLEFT', BrokerLDB.Frame, 'TOPRIGHT', 1, yOffSet)
		yOffSet = yOffSet - BrokerLDB.db['PanelHeight'] - 1
	end

	BrokerLDB.Frame:Height((BrokerLDB.db['PanelHeight'] * #BrokerLDB.Whitelist) + (#BrokerLDB.Whitelist - 1))
	if (#BrokerLDB.Buttons == 0 or #BrokerLDB.Whitelist == 0) then
		BrokerLDB.Frame:Hide()
	end

	if not BrokerLDB.db['MouseOver'] then
		UIFrameFadeIn(BrokerLDB.Frame, 0.2, BrokerLDB.Frame:GetAlpha(), 1)
	else
		UIFrameFadeOut(BrokerLDB.Frame, 0.2, BrokerLDB.Frame:GetAlpha(), 0)
	end
end

function BrokerLDB:AddBlacklistFrame(frame)
	frame.Enabled = false
	local index
	for i, v in pairs(BrokerLDB.Whitelist) do
		if v == frame:GetName() then
			index = i
			break
		end
	end
	tremove(BrokerLDB.Whitelist, index)
	tinsert(BrokerLDB.Blacklist, frame:GetName())
	BrokerLDB:SlideIn()
	BrokerLDB:Update()
end

function BrokerLDB:RemoveBlacklistFrame(frame)
	frame.Enabled = true
	local index
	for i, v in pairs(BrokerLDB.Blacklist) do
		if v == frame:GetName() then
			index = i
			break
		end
	end
	tremove(BrokerLDB.Blacklist, index)
	tinsert(BrokerLDB.Whitelist, frame)
	BrokerLDB:SlideIn()
	BrokerLDB:Update()
end

function BrokerLDB:New(_, Name, Object)
	if _G['BrokerLDB_'..Name] then return end
	for _, v in pairs(BrokerLDB.Ignore) do
		if Name == v then return end
	end

	local Frame = CreateFrame('Frame', 'BrokerLDB_'..Name, BrokerLDB.Frame)
	Frame:Hide()
	Frame.pluginName = Name
	Frame.pluginObject = Object

	Frame:SetFrameStrata('BACKGROUND')
	Frame:SetFrameLevel(3)
	Frame:SetTemplate('Transparent')
	BrokerLDB:AnimateSlide(Frame, -150, 0, 1)
	Frame:SetHeight(BrokerLDB.db['PanelHeight'])
	Frame:SetWidth(BrokerLDB.db['PanelWidth'])
	Frame.Enabled = true
	tinsert(BrokerLDB.Buttons, Frame)
	tinsert(BrokerLDB.Whitelist, Frame)

	Frame.Text = Frame:CreateFontString(nil, 'OVERLAY')
	Frame.Text:SetFont(PA.LSM:Fetch('font', BrokerLDB.db['Font']), BrokerLDB.db['FontSize'], BrokerLDB.db['FontFlag'])
	Frame.Text:SetPoint('CENTER', Frame)

	Frame.IconBackdrop = CreateFrame('Frame', nil, Frame)
	Frame.IconBackdrop:SetTemplate()

	Frame.Icon = Frame.IconBackdrop:CreateTexture(nil, 'ARTWORK')
	Frame.Icon:SetInside()
	Frame.Icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)

	BrokerLDB.PluginObjects[Name] = Frame.Text

	BrokerLDB:TextUpdate(nil, Name, nil, Object.text or Object.label or Name)
	PA.LDB.RegisterCallback(BrokerLDB, 'LibDataBroker_AttributeChanged_'..Name..'_text', 'TextUpdate')
	if Object.suffix then
		BrokerLDB:ValueUpdate(nil, Name, nil, Object.value or Name, Object)
		PA.LDB.RegisterCallback(BrokerLDB, 'LibDataBroker_AttributeChanged_'..Name..'_value', 'ValueUpdate')
	end

	Frame:SetScript('OnEnter', function(s)
		if s.anim:IsPlaying() then return end
		if s.pluginObject.OnTooltipShow then
			GameTooltip:SetOwner(s, 'ANCHOR_RIGHT' , 2, -(BrokerLDB.db['PanelHeight']))
			GameTooltip:SetTemplate('Transparent')
			GameTooltip:ClearLines()
			s.pluginObject.OnTooltipShow(GameTooltip, s)
			GameTooltip:Show()
		elseif s.pluginObject.OnEnter then
			GameTooltip:SetTemplate('Transparent')
			s.pluginObject.OnEnter(s)
		end
	end)
	Frame:SetScript('OnLeave', function(s)
		GameTooltip:Hide()
		if s.pluginObject.OnLeave then
			s.pluginObject.OnLeave(s)
		end
	end)
	Frame:SetScript('OnMouseUp', function(s, btn)
		if s.anim:IsPlaying() then return end
		if s.pluginObject.OnClick then
			s.pluginObject.OnClick(s, btn)
		end
	end)
	Frame:SetScript('OnUpdate', function(s) s.Icon:SetTexture(Object.icon) end)
	tinsert(BrokerLDB.EasyMenu, { text = 'Show '..Name, checked = function() return Frame.Enabled end, func = function() if Frame.Enabled then BrokerLDB:AddBlacklistFrame(Frame) else BrokerLDB:RemoveBlacklistFrame(Frame) end BrokerLDB:Update() end } )

	if Object.OnCreate then Object.OnCreate(Object, Frame) end
end

function BrokerLDB:GetOptions()
	PA.Options.args.BrokerLDB = {
		type = 'group',
		name = BrokerLDB.Title,
		desc = BrokerLDB.Description,
		get = function(info) return BrokerLDB.db[info[#info]] end,
		args = {
			Header = {
				order = 0,
				type = 'header',
				name = BrokerLDB.Header,
			},
			Enable = {
				order = 1,
				type = 'toggle',
				name = PA.ACL['Enable'],
				set = function(info, value)
					BrokerLDB.db[info[#info]] = value
					if (not BrokerLDB.isEnabled) then
						BrokerLDB:Initialize()
					else
						_G.StaticPopup_Show('PROJECTAZILROKA_RL')
					end
				end,
			},
			General = {
				order = 2,
				type = 'group',
				name = PA.ACL['General'],
				guiInline = true,
				set = function(info, value) BrokerLDB.db[info[#info]] = value BrokerLDB:Update() end,
				args = {
					ShowIcon = {
						order = 3,
						type = 'toggle',
						name = PA.ACL['Show Icon'],
					},
					MouseOver = {
						order = 4,
						type = 'toggle',
						name = PA.ACL['MouseOver'],
					},
					ShowText = {
						order = 5,
						type = 'toggle',
						name = PA.ACL['Show Text'],
					},
					PanelHeight = {
						order = 6,
						type = 'range',
						name = PA.ACL['Panel Height'],
						min = 20, max = 40, step = 1,
					},
					PanelWidth = {
						order = 8,
						type = 'range',
						name = PA.ACL['Panel Width'],
						min = 0, softMin = 140, max = 280, step = 1,
					},
					Font = {
						type = 'select', dialogControl = 'LSM30_Font',
						order = 9,
						name = PA.ACL['Font'],
						values = PA.LSM:HashTable('font'),
					},
					FontSize = {
						order = 10,
						name = FONT_SIZE,
						type = 'range',
						min = 8, max = 22, step = 1,
					},
					FontFlag = {
						name = PA.ACL['Font Outline'],
						order = 11,
						type = 'select',
						values = PA.FontFlags,
					},
				},
			},
			AuthorHeader = {
				order = -2,
				type = 'header',
				name = PA.ACL['Authors:'],
			},
			Authors = {
				order = -1,
				type = 'description',
				name = BrokerLDB.Authors,
				fontSize = 'large',
			},
		},
	}
end

function BrokerLDB:BuildProfile()
	PA.Defaults.profile.BrokerLDB = {
		Enable = false,
		PanelHeight = 20,
		PanelWidth = 140,
		MouseOver = false,
		ShowIcon = false,
		ShowText = true,
		Font = 'Tukui Pixel',
		FontSize = 12,
		FontFlag = 'MONOCHROMEOUTLINE',
	}
end

function BrokerLDB:Initialize()
	BrokerLDB.db = PA.db.BrokerLDB

	if BrokerLDB.db.Enable ~= true then
		return
	end

	BrokerLDB.isEnabled = true

	BrokerLDB.DropDown = CreateFrame('Frame', 'BrokerLDBDropDown', UIParent, 'UIDropDownMenuTemplate')
	BrokerLDB.Slide = 'In'
	BrokerLDB.EasyMenu = {}

	BrokerLDB.Buttons = {}
	BrokerLDB.PluginObjects = {}

	BrokerLDB.Ignore = { 'Cork' }

	BrokerLDB.Whitelist = {}
	BrokerLDB.Blacklist = {}

	PA.LDB.RegisterCallback(BrokerLDB, 'LibDataBroker_DataObjectCreated', 'New')

	local Frame = CreateFrame('Button', nil, UIParent)
	Frame.Arrow = Frame:CreateTexture(nil, 'OVERLAY')
	Frame.Arrow:SetTexture([[Interface\AddOns\ProjectAzilroka\Media\Textures\Arrow]])
	Frame.Arrow:SetSize(12, 12)
	Frame.Arrow:SetPoint('CENTER', Frame, 0, 0)
	Frame:SetFrameStrata('BACKGROUND')
	Frame:SetWidth(15)
	Frame:SetPoint('LEFT', UIParent, 'LEFT', 1, 0)
	Frame:RegisterForClicks('LeftButtonDown', 'RightButtonDown')
	Frame:SetTemplate('Transparent')
	BrokerLDB:AnimateSlide(Frame, -150, 0, 1)

	Frame:SetScript('OnEnter', function(s) UIFrameFadeIn(s, 0.2, s:GetAlpha(), 1) end)
	Frame:SetScript('OnLeave', function(s)
		if BrokerLDB.Slide == 'In' and BrokerLDB.db['MouseOver'] then
			UIFrameFadeOut(s, 0.2, s:GetAlpha(), 0)
		end
	end)

	Frame:SetScript('OnClick', function(s, btn)
		if s.anim:IsPlaying() then return end
		if btn == 'LeftButton' then
			if BrokerLDB.Slide == 'In' then
				BrokerLDB:SlideOut()
			else
				BrokerLDB:SlideIn()
			end
		else
			EasyMenu(BrokerLDB.EasyMenu, BrokerLDB.DropDown, 'cursor', 0, 0, 'MENU', 2)
		end
	end)

	BrokerLDB.Frame = Frame

	BrokerLDB:Update()
	BrokerLDB:SlideIn()
end
