local key = settings.get "gicr.key"
if not key then error "No SPUDNET key provided" end
local c = peripheral.find "chat_box"

local prefix = "\167bgollark (via GICR)\167r"

local ws
local function connect()
	if ws then pcall(ws.close) end
	local error_count = 0
	while true do
		print "Connecting to SPUDNET..."
		ws, err = http.websocket("wss://osmarks.tk/wsthing/GICR/comm", { authorization = "Key " .. key })
		if not ws then
			printError("Connection Error: " .. tostring(err))
			error_count = error_count + 1
			delay = math.pow(2, error_count)
			print(("Exponential backoff: waiting %d seconds."):format(delay))
			sleep(delay)
			print "Attempting reconnection..."
		else
			return
		end
	end
end

local function receive_ws()
	local ok, result = pcall(ws.receive)
	if not ok then
		printError "Receive Failure"
		printError(result)
		connect()
		return ws.receive()
	end
	return result
end

local function send_ws(message)
	local ok, result = pcall(ws.send, message)
	if not ok then
		printError "Send Failure"
		printError(result)
		connect()
		ws.send(message)
	end
	return result
end

local function chat_listener()
	send_ws "Connected."
	while true do
		local ev, p1, p2, p3 = os.pullEvent()
		if ev == "chat" then
			print("Chat message:", p1, p2)
			send_ws(("%s: %s"):format(p1, p2))
		elseif ev == "death" then
			print("Death:", p1, p2, p3)
			send_ws(("%s died due to entity %s cause %s"):format(p1, p2 or "[none]", p3 or "[none]"))
		elseif ev == "join" then
			print("Join:", p1)
			send_ws("+ " .. p1)
		elseif ev == "leave" then
			print("leave:", p1)
			send_ws("- " .. p1)
		end
	end
end

local function splitspace(str)
	local tokens = {}
	for token in string.gmatch(str, "[^%s]+") do
		table.insert(tokens, token)
	end
	return tokens
end

local function handle_command(tokens)
	local t = tokens[1]
	if t == "update" then
		local h = http.get("https://pastebin.com/raw/70w12805?" .. tostring(math.random(0, 100000)))
		local code = h.readAll()
		h.close()
		local ok, err = load(code, "@<code>")
		if err then error("syntax error in update: " .. err) end
		local f = fs.open("startup", "w")
		f.write(code)
		f.close()
		os.reboot()
	elseif t == "tell" then
		table.remove(tokens, 1)
		local user = table.remove(tokens, 1)
		local message = table.concat(tokens, " ")
		c.tell(user, message, prefix)
	elseif t == "prefix" then
		table.remove(tokens, 1)
		local prefix = table.remove(tokens, 1)
		local message = table.concat(tokens, " ")
		c.say(message, prefix)
	elseif t == "list" then
		local list = c.getPlayerList()
		send_ws(("Player list: %s"):format(table.concat(list, " ")))
	end
end

local function ws_listener()
	while true do
		local message = receive_ws()
		print("Received", message)
		local fst = message:sub(1, 1)
		if fst == "/" then
			local rest = message:sub(2)
			print("Executing", rest)
			local tokens = splitspace(rest)
			local ok, err = pcall(handle_command, tokens)
			if not ok then printError(err) end
		else
			c.say(message, prefix)
		end
	end
end

connect()

parallel.waitForAll(chat_listener, ws_listener)