NUiKills = {}

local ANIM_DURATION = 0.2

function NUiKills:SetupUI()
	require("nui-hud")
	self.Active = false
	self.DigitStates = nil
	self.DigitTextures = nil
	self.LastDrawTime = nil
	self.LastKillStr = nil
	self:ParseConfig("nui-hud.tbl")
end

function NUiKills:ParseConfig(file)
	NUi:ParseGeneralSettings(file, self)
	NUi:ParseConfigSection(file, "#Kill Counter Settings", function() self:ConfigKillCounter() end)
end

function NUiKills:ConfigKillCounter()
	local t = { Graphic = {}, Colors = {} }

	if parse.optionalString("$Frame Positioning:") then
		t.Graphic.Frame = NUi:ParseGraphicBlock(self.ScaleFactor)
	end

	if parse.optionalString("$Label Positioning:") then
		t.Graphic.Label = NUi:ParseGraphicBlock(self.ScaleFactor)
	end

	if parse.optionalString("$Divider Positioning:") then
		t.Graphic.Divider = NUi:ParseGraphicBlock(self.ScaleFactor)
	end

	if parse.optionalString("$Divider Color:") then
		local rgba = NUi:GetCSV(parse.getString())
		t.Colors.Divider = { tonumber(rgba[1]), tonumber(rgba[2]), tonumber(rgba[3]), tonumber(rgba[4]) or 255 }
	else
		t.Colors.Divider = { 127, 127, 127, 255 }
	end

	if parse.optionalString("$Frame Colors:") then
		t.Colors.Frame = NUi:ParseColorBlock()
	else
		t.Colors.Frame = { Mode = "lerp", Colors = {{7, 39, 1, 217}} }
	end

	if parse.optionalString("$Label Color:") then
		local rgba = NUi:GetCSV(parse.getString())
		t.Colors.Label = {rgba[1], rgba[2], rgba[3], rgba[4] or 255}
	else
		t.Colors.Label = {255, 255, 255, 255}
	end

	if parse.optionalString("$Text Color:") then
		local rgba = NUi:GetCSV(parse.getString())
		t.Colors.Text = {rgba[1], rgba[2], rgba[3], rgba[4] or 255}
	else
		t.Colors.Text = {255, 255, 255, 255}
	end

	if parse.optionalString("$Text Offset:") then
		local off = NUi:GetCSV(parse.getString())
		t.TextOffset = {(tonumber(off[1]) or 30) * self.ScaleFactor, (tonumber(off[2]) or 10) * self.ScaleFactor}
	else
		t.TextOffset = {30 * self.ScaleFactor, 10 * self.ScaleFactor}
	end

	if parse.optionalString("$Digit Step:") then
		t.DigitStep = parse.getFloat() * self.ScaleFactor
	else
		t.DigitStep = 0
	end

	if parse.optionalString("$Text Angle:") then
		t.TextAngle = parse.getFloat() * math.pi / 180
	else
		t.TextAngle = 0
	end

	if parse.optionalString("$Font Scale:") then
		t.FontScale = parse.getFloat() * self.ScaleFactor
	else
		t.FontScale = self.ScaleFactor
	end

	parse.requiredString("#End")
	self.KillCounter = t
	self.Active = true
end

function NUiKills:InitDigits()
	local kc = self.KillCounter
	local fs = kc.FontScale

	gr.CurrentFont = self.KillFont
	self.DigitTextures = {}
	local maxW = 0
	for i = 0, 9 do
		local c = tostring(i)
		local tw = gr.getStringWidth(c)
		local th = self.KillFont.Height
		local pad = th
		local tex = gr.createTexture(tw + pad * 2, th + pad * 2, TEXTURE_STATIC)
		gr.CurrentRenderTarget = tex
		gr.setColor(0, 0, 0, 255)
		gr.drawRectangle(0, 0, tw + pad * 2, th + pad * 2, true)
		gr.setColor(255, 255, 255, 255)
		gr.CurrentFont = self.KillFont
		gr.drawString(c, pad, pad)
		gr.CurrentRenderTarget = nil
		tex:destroyRenderTarget()
		self.DigitTextures[c] = { tex = tex, tw = tw, th = th, pad = pad }
		if tw > maxW then maxW = tw end
	end

	if kc.DigitStep > 0 then
		self.SlotWidth = kc.DigitStep
	else
		local pad = self.KillFont.Height
		self.SlotWidth = (maxW + pad) * fs
	end

	self.DigitStates = {}
	for i = 1, 4 do
		self.DigitStates[i] = { Char = "0", OldChar = "0", AnimT = 1.0 }
	end
	self.LastKillStr = "0000"
end

function NUiKills:UpdateDigits(newKillStr, dt)
	for i = 1, 4 do
		local state = self.DigitStates[i]
		if state.AnimT < 1 then
			state.AnimT = math.min(1, state.AnimT + dt / ANIM_DURATION)
		end
		local newChar = string.sub(newKillStr, i, i)
		if newChar ~= state.Char then
			state.OldChar = state.Char
			state.Char = newChar
			state.AnimT = 0
		end
	end
end

function NUiKills:DrawDigit(state, x, baseY, fs, angle, color)
	gr.setColor(color[1], color[2], color[3], color[4])

	local slotCenterX = x + self.SlotWidth / 2

	local function drawScaled(entry, scaleX)
		scaleX = math.max(scaleX, 0.02)
		local sw, sh, sp = entry.tw * fs, entry.th * fs, entry.pad * fs
		local halfW = (sw / 2 + sp) * scaleX
		gr.drawImage(entry.tex, slotCenterX - halfW, baseY - sp, slotCenterX + halfW, baseY + sh + sp, 0, 0, 1, 1, 1, true, angle)
	end

	if state.AnimT >= 1 then
		local ne = self.DigitTextures[state.Char]
		if ne then
			local sw, sh, sp = ne.tw * fs, ne.th * fs, ne.pad * fs
			local cx = slotCenterX - sw / 2
			gr.drawImage(ne.tex, cx - sp, baseY - sp, cx + sw + sp, baseY + sh + sp, 0, 0, 1, 1, 1, true, angle)
		end
	elseif state.AnimT < 0.5 then
		local scaleX = 1.0 - state.AnimT * 2
		local oe = self.DigitTextures[state.OldChar]
		if oe then drawScaled(oe, scaleX) end
	else
		local scaleX = (state.AnimT - 0.5) * 2
		local ne = self.DigitTextures[state.Char]
		if ne then drawScaled(ne, scaleX) end
	end
end

function NUiKills:Draw()
	if not self.Active or not self.KillCounter then return end
	local kc = self.KillCounter

	if kc.Graphic.Frame then
		local frameEl = {
			Position   = { x = kc.Graphic.Frame.Position.x, y = kc.Graphic.Frame.Position.y },
			Offset     = { x = kc.Graphic.Frame.Offset[1], y = kc.Graphic.Frame.Offset[2] },
			Dimensions = { Width = kc.Graphic.Frame.Width, Height = kc.Graphic.Frame.Height },
			Image      = kc.Graphic.Frame.File,
			Color      = NUi:ResolveColor(kc.Colors.Frame, 1),
			Direction  = NUi.Direction.RIGHT,
			Percentage = 1
		}
		NUi:DrawHudElement(frameEl)
	end

	if kc.Graphic.Divider then
		local divEl = {
			Position   = { x = kc.Graphic.Divider.Position.x, y = kc.Graphic.Divider.Position.y },
			Offset     = { x = kc.Graphic.Divider.Offset[1],  y = kc.Graphic.Divider.Offset[2] },
			Dimensions = { Width = kc.Graphic.Divider.Width,   Height = kc.Graphic.Divider.Height },
			Image      = kc.Graphic.Divider.File,
			Color      = kc.Colors.Divider,
			Direction  = NUi.Direction.RIGHT,
			Percentage = 1
		}
		NUi:DrawHudElement(divEl)
	end

	if kc.Graphic.Label then
		local labelEl = {
			Position   = { x = kc.Graphic.Label.Position.x, y = kc.Graphic.Label.Position.y },
			Offset     = { x = kc.Graphic.Label.Offset[1], y = kc.Graphic.Label.Offset[2] },
			Dimensions = { Width = kc.Graphic.Label.Width, Height = kc.Graphic.Label.Height },
			Image      = kc.Graphic.Label.File,
			Color      = kc.Colors.Label,
			Direction  = NUi.Direction.RIGHT,
			Percentage = 1
		}
		NUi:DrawHudElement(labelEl)
	end

	if not self.KillFont then
		for i = 1, #gr.Fonts do
			if gr.Fonts[i].Name == "CommChatLarge" then
				self.KillFont = gr.Fonts[i]
				break
			end
		end
	end

	if not self.KillFont then return end

	if not self.DigitStates then
		self:InitDigits()
	end

	local now = mn.getMissionTime()
	local dt = math.min(now - (self.LastDrawTime or now), 0.1)
	self.LastDrawTime = now

	local kills = math.min(ba.getCurrentPlayer().Stats.MissionTotalKills, 9999)
	local killStr = string.format("%04d", kills)
	self:UpdateDigits(killStr, dt)

	local fs = kc.FontScale
	local fp = kc.Graphic.Frame.Position
	local startX = fp.x + kc.TextOffset[1]
	local baseY  = fp.y + kc.TextOffset[2]
	local angle  = kc.TextAngle
	local cosA   = math.cos(angle)
	local sinA   = math.sin(angle)
	local centerX = startX + 1.5 * self.SlotWidth
	local centerY = baseY

	for i = 1, 4 do
		local rawX = startX + (i - 1) * self.SlotWidth
		local dx = rawX - centerX
		local rx = centerX + dx * cosA
		local ry = centerY + dx * sinA
		self:DrawDigit(self.DigitStates[i], rx, ry, fs, angle, kc.Colors.Text)
	end
end
