love.mqtt = {}

local mqttEventChannel
local mqttCommandChannel
local errorMessage = nil

local oldPrint = print

function print(...)
	local string = string.format(...)
	love.mqtt.send("controller/stdout", string)
	oldPrint(...)
end

function printTable(table, indentation)
	indentation = indentation or ""
	for name, value in pairs(table) do
		print(indentation .. tostring(name) .. ": " .. tostring(value))
	end
end

function safeCall(target, ...)
	local success, msg = pcall(target, ...)
	if not success then
		errorMessage = msg
	end
end

function love.draw(...)
	if love.draw2 and not errorMessage then
		safeCall(love.draw2, ...)
	else
		local text = "Awaiting payload..."
		local font = love.graphics.getFont()

		if errorMessage then
			text = errorMessage
		end

		-- Calculate the center of the screen
		local centerX = love.graphics.getWidth() / 2
		local centerY = love.graphics.getHeight() / 2

		-- Calculate textX and textY
		local textX = math.floor(centerX - (font:getWidth(text) / 2))
		local textY = math.floor(centerY - (font:getHeight(text) / 2))
		
		local realText
		if errorMessage then
			realText = errorMessage
		else
			realText = "Awaiting payload" .. ("."):rep(math.floor(love.timer.getTime() * 4 % 4))
		end

		-- Render text
		if errorMessage then
			love.graphics.setBackgroundColor(0.2, 0, 0, 0)
		else
			love.graphics.setBackgroundColor(0, 0, 0.2, 0)
		end
		love.graphics.print(realText, textX, textY)
	end
end

function love.update(...)
	local message = mqttEventChannel:pop()
	if message then
		safeCall(love.mqtt[message.target], unpack(message.args))
	end

	if love.update2 and not errorMessage then
		safeCall(love.update2, ...)
	end
end

function love.mqtt.connect(connack)
	if connack.rc ~= 0 then
		print("Connection to broker failed:", connack:reason_string())
	end

	love.mqtt.subscribe("controller/payload")
	print("Connected to MQTT")
	printTable(connack)
end

function love.mqtt.message2(topic, payload)
	if topic == "controller/payload" then
		errorMessage = nil
		local success = love.filesystem.unmount("client.zip")
		if not success then
			print("Could not unmount client.zip")
		end
		local archive = love.filesystem.newFileData(payload, "client.zip")
		local success = love.filesystem.mount(archive, "client", true)
		if not success then
			print("Failed to mount archive")
			return
		end
		print("Archive mounted")
		local chunk, errormsg = love.filesystem.load("client/main.lua", "bt")
		if errormsg then
			print(errormsg)
			errorMessage = errormsg
			return
		end
		love.load = nil
		chunk()
		if love.load then
			safeCall(love.load)
		end
	elseif love.mqtt.message then
		love.mqtt.message(topic, payload)
	end
end

function love.mqtt.send(topic, arg)
	mqttCommandChannel:push {
		command = "send",
		topic = topic,
		arg = arg
	}
end

function love.mqtt.subscribe(topic)
	mqttCommandChannel:push {
		command = "subscribe",
		topic = topic,
	}
end

function love.load()
	love.graphics.setFont(love.graphics.newFont(20))
	local requirePaths = love.filesystem.getRequirePath()
	love.filesystem.setRequirePath(requirePaths .. ";client/?.lua;client/?/init.lua")
	local mqttThread = love.thread.newThread("mqttthread.lua")
	mqttThread:start()
	mqttEventChannel = love.thread.getChannel("mqtt_event")
	mqttCommandChannel = love.thread.getChannel("mqtt_command")
end
