local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local UF = E:GetModule('UnitFrames');

local max = max
local unpack = unpack
local CreateFrame = CreateFrame
local UnitHasVehicleUI = UnitHasVehicleUI
local MAX_COMBO_POINTS = MAX_COMBO_POINTS
-- GLOBALS: ElvUF_Player

local _, ns = ...
local ElvUF = ns.oUF
assert(ElvUF, 'ElvUI was unable to locate oUF.')

function UF:PostVisibility_ClassBars(frame)
	if not (frame and frame.db) then return end

	UF:Configure_ClassBar(frame)
	UF:Configure_Power(frame)
	UF:Configure_InfoPanel(frame)
end

function UF:Configure_ClassBar(frame)
	local db = frame.db
	if not db then return end

	local bars = frame[frame.ClassBar]
	if not bars then return end

	bars.Holder = frame.ClassBarHolder
	bars.origParent = frame

	--Fix height in case it is lower than the theme allows, or in case it's higher than 30px when not detached
	if not UF.thinBorders and (frame.CLASSBAR_HEIGHT > 0 and frame.CLASSBAR_HEIGHT < 7) then --A height of 7 means 6px for borders and just 1px for the actual power statusbar
		frame.CLASSBAR_HEIGHT = 7
		if db.classbar then db.classbar.height = 7 end
	elseif UF.thinBorders and (frame.CLASSBAR_HEIGHT > 0 and frame.CLASSBAR_HEIGHT < 3) then --A height of 3 means 2px for borders and just 1px for the actual power statusbar
		frame.CLASSBAR_HEIGHT = 3
		if db.classbar then db.classbar.height = 3 end
	elseif not frame.CLASSBAR_DETACHED and frame.CLASSBAR_HEIGHT > 30 then
		frame.CLASSBAR_HEIGHT = 10
		if db.classbar then db.classbar.height = 10 end
	end

	-- keep after classbar height update
	UF.ToggleResourceBar(bars)

	--We don't want to modify the original frame.CLASSBAR_WIDTH value, as it bugs out when the classbar gains more buttons
	local CLASSBAR_WIDTH = frame.CLASSBAR_WIDTH
	local SPACING = (UF.BORDER + UF.SPACING)*2

	local color = E.db.unitframe.colors.borderColor
	if not bars.backdrop.forcedBorderColors then
		bars.backdrop:SetBackdropBorderColor(color.r, color.g, color.b)
	end

	if frame.USE_MINI_CLASSBAR and not frame.CLASSBAR_DETACHED then
		if frame.MAX_CLASS_BAR == 1 or frame.ClassBar == 'AdditionalPower' or frame.ClassBar == 'Stagger' or frame.ClassBar == 'AlternativePower' then
			CLASSBAR_WIDTH = CLASSBAR_WIDTH * 2/3
		else
			CLASSBAR_WIDTH = CLASSBAR_WIDTH * (frame.MAX_CLASS_BAR - 1) / frame.MAX_CLASS_BAR
		end
	elseif frame.CLASSBAR_DETACHED then --Detached
		CLASSBAR_WIDTH = db.classbar.detachedWidth
	end

	bars:Width(CLASSBAR_WIDTH - SPACING)
	bars:Height(frame.CLASSBAR_HEIGHT - SPACING)

	if frame.ClassBar == 'ClassPower' or frame.ClassBar == 'Runes' then
		if E.myclass == 'DEATHKNIGHT' and frame.ClassBar == 'Runes' then
			bars.sortOrder = (db.classbar.sortDirection ~= 'NONE') and db.classbar.sortDirection
		end

		local maxClassBarButtons = max(UF.classMaxResourceBar[E.myclass] or 0, MAX_COMBO_POINTS)
		for i = 1, maxClassBarButtons do
			bars[i].backdrop:Hide()

			if i <= frame.MAX_CLASS_BAR then
				if not bars[i].backdrop.forcedBorderColors then
					bars[i].backdrop:SetBackdropBorderColor(color.r, color.g, color.b)
				end

				bars[i]:Height(bars:GetHeight())
				if frame.MAX_CLASS_BAR == 1 then
					bars[i]:Width(CLASSBAR_WIDTH)
				elseif frame.USE_MINI_CLASSBAR then
					if frame.CLASSBAR_DETACHED and db.classbar.orientation == 'VERTICAL' then
						bars[i]:Width(CLASSBAR_WIDTH)
					else
						bars[i]:Width((CLASSBAR_WIDTH - ((5 + (UF.BORDER*2 + UF.SPACING*2))*(frame.MAX_CLASS_BAR - 1)))/frame.MAX_CLASS_BAR) --Width accounts for 5px spacing between each button, excluding borders
					end
				elseif i ~= frame.MAX_CLASS_BAR then
					bars[i]:Width((CLASSBAR_WIDTH - ((frame.MAX_CLASS_BAR-1)*(UF.BORDER*2-UF.SPACING))) / frame.MAX_CLASS_BAR) --classbar width minus total width of dividers between each button, divided by number of buttons
				end

				bars[i]:GetStatusBarTexture():SetHorizTile(false)
				bars[i]:ClearAllPoints()
				if i == 1 then
					bars[i]:Point('LEFT', bars)
				else
					if frame.USE_MINI_CLASSBAR then
						if frame.CLASSBAR_DETACHED and db.classbar.orientation == 'VERTICAL' then
							bars[i]:Point('BOTTOM', bars[i-1], 'TOP', 0, (db.classbar.spacing + UF.BORDER*2 + UF.SPACING*2))
						else
							bars[i]:Point('LEFT', bars[i-1], 'RIGHT', (db.classbar.spacing + UF.BORDER*2 + UF.SPACING*2), 0) --5px spacing between borders of each button(replaced with Detached Spacing option)
						end
					elseif i == frame.MAX_CLASS_BAR then
						bars[i]:Point('LEFT', bars[i-1], 'RIGHT', UF.BORDER-UF.SPACING, 0)
						bars[i]:Point('RIGHT', bars)
					else
						bars[i]:Point('LEFT', bars[i-1], 'RIGHT', UF.BORDER-UF.SPACING, 0)
					end
				end

				if not frame.USE_MINI_CLASSBAR then
					bars[i].backdrop:Hide()
				else
					bars[i].backdrop:Show()
				end

				if E.myclass == 'MONK' then
					bars[i]:SetStatusBarColor(unpack(ElvUF.colors.ClassBars[E.myclass][i]))
				elseif E.myclass == 'PALADIN' or E.myclass == 'MAGE' or E.myclass == 'WARLOCK' then
					bars[i]:SetStatusBarColor(unpack(ElvUF.colors.ClassBars[E.myclass]))
				elseif E.myclass == 'DEATHKNIGHT' and frame.ClassBar == 'Runes' then
					local r, g, b = unpack(ElvUF.colors.ClassBars.DEATHKNIGHT)
					bars[i]:SetStatusBarColor(r, g, b)
					if bars[i].bg then
						local mu = bars[i].bg.multiplier or 1
						bars[i].bg:SetVertexColor(r * mu, g * mu, b * mu)
					end
				else -- Combo Points for everyone else
					local r1, g1, b1 = unpack(ElvUF.colors.ComboPoints[1])
					local r2, g2, b2 = unpack(ElvUF.colors.ComboPoints[2])
					local r3, g3, b3 = unpack(ElvUF.colors.ComboPoints[3])
					local maxComboPoints = ((frame.MAX_CLASS_BAR == 10 and 10) or (frame.MAX_CLASS_BAR > 5 and 6 or 5))

					bars[i]:SetStatusBarColor(ElvUF:ColorGradient(i, maxComboPoints, r1, g1, b1, r2, g2, b2, r3, g3, b3))
				end

				if frame.CLASSBAR_DETACHED and db.classbar.verticalOrientation then
					bars[i]:SetOrientation('VERTICAL')
				else
					bars[i]:SetOrientation('HORIZONTAL')
				end

				--Fix missing backdrop colors on Combo Points when using Spaced style
				if frame.ClassBar == 'ClassPower' then
					if frame.USE_MINI_CLASSBAR then
						bars[i].bg:SetParent(bars[i].backdrop)
					else
						bars[i].bg:SetParent(bars)
					end
				end
			end
		end

		if (not frame.USE_MINI_CLASSBAR) and frame.USE_CLASSBAR then
			bars.backdrop:Show()
		else
			bars.backdrop:Hide()
		end
	elseif frame.ClassBar == 'AdditionalPower' or frame.ClassBar == 'Stagger' or frame.ClassBar == 'AlternativePower' then
		if frame.CLASSBAR_DETACHED and db.classbar.verticalOrientation then
			bars:SetOrientation('VERTICAL')
		else
			bars:SetOrientation('HORIZONTAL')
		end
	end

	if frame.USE_MINI_CLASSBAR and not frame.CLASSBAR_DETACHED then
		bars:ClearAllPoints()
		bars:Point('CENTER', frame.Health.backdrop, 'TOP', 0, 0)

		bars:SetFrameLevel(50) --RaisedElementParent uses 100, we want it lower than this

		if bars.Holder and bars.Holder.mover then
			E:DisableMover(bars.Holder.mover:GetName())
		end
	elseif frame.CLASSBAR_DETACHED then
		bars.Holder:Size(db.classbar.detachedWidth, db.classbar.height)

		bars:ClearAllPoints()
		bars:Point('BOTTOMLEFT', bars.Holder, 'BOTTOMLEFT', UF.BORDER + UF.SPACING, UF.BORDER + UF.SPACING)

		if not bars.Holder.mover then
			E:CreateMover(bars.Holder, 'ClassBarMover', L["Classbar"], nil, nil, nil, 'ALL,SOLO', nil, 'unitframe,individualUnits,player,classbar')
		else
			E:EnableMover(bars.Holder.mover:GetName())
		end

		if not db.classbar.strataAndLevel.useCustomStrata then
			bars:SetFrameStrata('LOW')
		else
			bars:SetFrameStrata(db.classbar.strataAndLevel.frameStrata)
		end

		if not db.classbar.strataAndLevel.useCustomLevel then
			bars:SetFrameLevel(frame.Health:GetFrameLevel() + 10) --Health uses 10, Power uses (Health + 5) when attached
		else
			bars:SetFrameLevel(db.classbar.strataAndLevel.frameLevel)
		end
	else
		bars:ClearAllPoints()
		if frame.ORIENTATION == 'RIGHT' then
			bars:Point('BOTTOMRIGHT', frame.Health.backdrop, 'TOPRIGHT', -UF.BORDER, UF.SPACING*3)
		else
			bars:Point('BOTTOMLEFT', frame.Health.backdrop, 'TOPLEFT', UF.BORDER, UF.SPACING*3)
		end

		bars:SetFrameStrata('LOW')
		bars:SetFrameLevel(frame.Health:GetFrameLevel() + 10) --Health uses 10, Power uses (Health + 5) when attached

		if bars.Holder and bars.Holder.mover then
			E:DisableMover(bars.Holder.mover:GetName())
		end
	end

	if frame.CLASSBAR_DETACHED and db.classbar.parent == 'UIPARENT' then
		E.FrameLocks[bars] = true
		bars:SetParent(E.UIParent)
	else
		E.FrameLocks[bars] = nil
		bars:SetParent(frame)
	end

	if frame.USE_CLASSBAR then
		if frame.ClassPower and not frame:IsElementEnabled('ClassPower') then
			frame:EnableElement('ClassPower')
		end
		if frame.AdditionalPower and not frame:IsElementEnabled('AdditionalPower') then
			frame:EnableElement('AdditionalPower')
		end
		if frame.Runes and not frame:IsElementEnabled('Runes') then
			frame:EnableElement('Runes')
		end
		if frame.Stagger and not frame:IsElementEnabled('Stagger') then
			frame:EnableElement('Stagger')
		end
		if frame.AlternativePower and not frame:IsElementEnabled('AlternativePower') then
			frame:EnableElement('AlternativePower')
		end
	else
		if frame.ClassPower and frame:IsElementEnabled('ClassPower') then
			frame:DisableElement('ClassPower')
		end
		if frame.AdditionalPower and frame:IsElementEnabled('AdditionalPower') then
			frame:DisableElement('AdditionalPower')
		end
		if frame.Runes and frame:IsElementEnabled('Runes') then
			frame:DisableElement('Runes')
		end
		if frame.Stagger and frame:IsElementEnabled('Stagger') then
			frame:DisableElement('Stagger')
		end
		if frame.AlternativePower and frame:IsElementEnabled('AlternativePower') then
			frame:DisableElement('AlternativePower')
		end
	end
end

local function ToggleResourceBar(bars)
	local frame = bars.origParent or bars:GetParent()

	local db = frame.db
	if not db then return end

	frame.CLASSBAR_SHOWN = frame[frame.ClassBar]:IsShown()

	if bars.text then bars.text:SetAlpha(frame.CLASSBAR_SHOWN and 1 or 0) end

	frame.CLASSBAR_HEIGHT = frame.USE_CLASSBAR and ((db.classbar and db.classbar.height) or (frame.AlternativePower and db.power.height)) or 0
	frame.CLASSBAR_YOFFSET = (not frame.USE_CLASSBAR or not frame.CLASSBAR_SHOWN or frame.CLASSBAR_DETACHED) and 0 or (frame.USE_MINI_CLASSBAR and ((UF.SPACING+(frame.CLASSBAR_HEIGHT/2))) or (frame.CLASSBAR_HEIGHT - (UF.BORDER-UF.SPACING)))

	UF:Configure_CustomTexts(frame)
	UF:Configure_HealthBar(frame)
	UF:Configure_Portrait(frame)

	-- keep this after the configure_healtbar, we need the one updated before we match the healpred size to -1
	if frame.HealthPrediction then
		UF:SetSize_HealComm(frame)
	end
end
UF.ToggleResourceBar = ToggleResourceBar --Make available to combobar

-------------------------------------------------------------
-- MONK, PALADIN, WARLOCK, MAGE, and COMBOS
-------------------------------------------------------------
function UF:Construct_ClassBar(frame)
	local bars = CreateFrame('Frame', '$parent_ClassBar', frame, 'BackdropTemplate')
	bars:CreateBackdrop(nil, nil, nil, nil, true)
	bars:Hide()

	local maxBars = max(UF.classMaxResourceBar[E.myclass] or 0, MAX_COMBO_POINTS)
	for i = 1, maxBars do
		bars[i] = CreateFrame('StatusBar', frame:GetName()..'ClassIconButton'..i, bars)
		bars[i]:SetStatusBarTexture(E.media.blankTex) --Dummy really, this needs to be set so we can change the color
		bars[i]:GetStatusBarTexture():SetHorizTile(false)
		UF.statusbars[bars[i]] = true

		bars[i]:CreateBackdrop(nil, nil, nil, nil, true)
		bars[i].backdrop:SetParent(bars)

		bars[i].bg = bars:CreateTexture(nil, 'BORDER')
		bars[i].bg:SetAllPoints(bars[i])
		bars[i].bg:SetTexture(E.media.blankTex)
	end

	bars.PostVisibility = UF.PostVisibilityClassBar
	bars.PostUpdate = UF.UpdateClassBar
	bars.UpdateColor = E.noop --We handle colors on our own in Configure_ClassBar
	bars.UpdateTexture = E.noop --We don't use textures but statusbars, so prevent errors

	bars:SetScript('OnShow', ToggleResourceBar)
	bars:SetScript('OnHide', ToggleResourceBar)

	return bars
end

function UF:PostVisibilityClassBar()
	UF:PostVisibility_ClassBars(self.origParent or self:GetParent())
end

function UF:UpdateClassBar(current, maxBars, hasMaxChanged)
	local frame = self.origParent or self:GetParent()
	local db = frame.db
	if not db then return end

	local isShown = self:IsShown()
	local stateChanged

	if not frame.USE_CLASSBAR or (current == 0 and db.classbar.autoHide) or maxBars == nil then
		self:Hide()
		if isShown then
			stateChanged = true
		end
	else
		self:Show()
		if not isShown then
			stateChanged = true
		end
	end

	if hasMaxChanged then
		frame.MAX_CLASS_BAR = maxBars
		UF:Configure_ClassBar(frame, current)
	elseif stateChanged then
		UF:Configure_ClassBar(frame, current)
	end

	local custom_backdrop = UF.db.colors.customclasspowerbackdrop and UF.db.colors.classpower_backdrop
	for i=1, #self do
		if custom_backdrop then
			self[i].bg:SetVertexColor(custom_backdrop.r, custom_backdrop.g, custom_backdrop.b)
		else
			local r, g, b = self[i]:GetStatusBarColor()
			self[i].bg:SetVertexColor(r * .35, g * .35, b * .35)
		end

		if maxBars and (i <= maxBars) then
			self[i].bg:Show()
		else
			self[i].bg:Hide()
		end
	end
end

-------------------------------------------------------------
-- DEATHKNIGHT
-------------------------------------------------------------
local function PostUpdateRunes(self)
	local useRunes = not UnitHasVehicleUI('player')
	if useRunes then
		self:Show()
	else
		self:Hide()
	end

	local custom_backdrop = UF.db.colors.customclasspowerbackdrop and UF.db.colors.classpower_backdrop
	for i=1, #self do
		if custom_backdrop then
			self[i].bg:SetVertexColor(custom_backdrop.r, custom_backdrop.g, custom_backdrop.b)
		else
			local r, g, b = self[i]:GetStatusBarColor()
			self[i].bg:SetVertexColor(r * .35, g * .35, b * .35)
		end
	end
end

function UF:Construct_DeathKnightResourceBar(frame)
	local runes = CreateFrame('Frame', '$parent_Runes', frame)
	runes:CreateBackdrop(nil, nil, nil, nil, true)
	runes.backdrop:Hide()

	for i = 1, UF.classMaxResourceBar[E.myclass] do
		runes[i] = CreateFrame('StatusBar', frame:GetName()..'RuneButton'..i, runes)
		runes[i]:SetStatusBarTexture(E.media.blankTex)
		runes[i]:GetStatusBarTexture():SetHorizTile(false)
		UF.statusbars[runes[i]] = true

		runes[i]:CreateBackdrop(nil, nil, nil, nil, true)
		runes[i].backdrop:SetParent(runes)

		runes[i].bg = runes[i]:CreateTexture(nil, 'BORDER')
		runes[i].bg:SetAllPoints()
		runes[i].bg:SetTexture(E.media.blankTex)
		runes[i].bg.multiplier = 0.35
	end

	runes.PostUpdate = PostUpdateRunes
	runes.UpdateColor = E.noop --We handle colors on our own in Configure_ClassBar
	runes:SetScript('OnShow', ToggleResourceBar)
	runes:SetScript('OnHide', ToggleResourceBar)

	return runes
end

-------------------------------------------------------------
-- ALTERNATIVE MANA BAR
-------------------------------------------------------------
function UF:Construct_AdditionalPowerBar(frame)
	local additionalPower = CreateFrame('StatusBar', '$parent_AdditionalPowerBar', frame)
	additionalPower.colorPower = true
	additionalPower.frequentUpdates = true
	additionalPower.PostUpdate = UF.PostUpdateAdditionalPower
	additionalPower.PostUpdateColor = UF.PostColorAdditionalPower
	additionalPower.PostVisibility = UF.PostVisibilityAdditionalPower
	additionalPower:CreateBackdrop(nil, nil, nil, nil, true)
	additionalPower:SetStatusBarTexture(E.media.blankTex)
	UF.statusbars[additionalPower] = true

	additionalPower.RaisedElementParent = CreateFrame('Frame', nil, additionalPower)
	additionalPower.RaisedElementParent:SetFrameLevel(additionalPower:GetFrameLevel() + 100)
	additionalPower.RaisedElementParent:SetAllPoints()

	additionalPower.text = additionalPower.RaisedElementParent:CreateFontString(nil, 'OVERLAY')
	UF:Configure_FontString(additionalPower.text)

	additionalPower.bg = additionalPower:CreateTexture(nil, 'BORDER')
	additionalPower.bg:SetAllPoints(additionalPower)
	additionalPower.bg:SetTexture(E.media.blankTex)
	additionalPower.bg.multiplier = 0.35

	additionalPower:SetScript('OnShow', ToggleResourceBar)
	additionalPower:SetScript('OnHide', ToggleResourceBar)

	return additionalPower
end

function UF:PostColorAdditionalPower()
	local frame = self.origParent or self:GetParent()
	if frame.USE_CLASSBAR then
		local custom_backdrop = UF.db.colors.customclasspowerbackdrop and UF.db.colors.classpower_backdrop
		if custom_backdrop then
			self.bg:SetVertexColor(custom_backdrop.r, custom_backdrop.g, custom_backdrop.b)
		end
	end
end

function UF:PostUpdateAdditionalPower(CUR, MAX, event)
	local frame = self.origParent or self:GetParent()
	local db = frame.db

	if frame.USE_CLASSBAR and event ~= 'ElementDisable' and (CUR ~= MAX or not db.classbar.autoHide) then
		self:Show()
	else
		self:Hide()
	end
end

function UF:PostVisibilityAdditionalPower(enabled)
	local frame = self.origParent or self:GetParent()

	frame.ClassBar = (enabled and 'AdditionalPower') or 'ClassPower'

	UF:PostVisibility_ClassBars(frame)
end

-----------------------------------------------------------
-- Stagger Bar
-----------------------------------------------------------
function UF:Construct_Stagger(frame)
	local stagger = CreateFrame('Statusbar', '$parent_Stagger', frame)
	stagger:CreateBackdrop(nil,nil, nil, nil, true)
	stagger.PostUpdate = UF.PostUpdateStagger
	stagger.PostVisibility = UF.PostUpdateVisibilityStagger
	UF.statusbars[stagger] = true

	stagger:SetScript('OnShow', ToggleResourceBar)
	stagger:SetScript('OnHide', ToggleResourceBar)

	return stagger
end

function UF:PostUpdateStagger(stagger)
	local frame = self.origParent or self:GetParent()
	local db = frame.db

	if not frame.USE_CLASSBAR or (stagger == 0 and db.classbar.autoHide) then
		self:Hide()
	else
		self:Show()
	end
end

function UF:PostUpdateVisibilityStagger(_, _, isShown, stateChanged)
	self.ClassBar = (isShown and 'Stagger') or 'ClassPower'

	if stateChanged then
		UF:PostVisibility_ClassBars(self)
	end
end
