PyuTest.DEFAULT_PLAYER_STATS = {
	attack = 1,
	defense = 1,
}

PyuTest.get_player_stats = function(player)
	local meta = player:get_meta()
	return core.deserialize(meta:get("stats") or core.serialize(PyuTest.DEFAULT_PLAYER_STATS))
end

PyuTest.save_player_stats = function(player, stats)
	local meta = player:get_meta()
	meta:set_string("stats", core.serialize(stats))
end

PyuTest.set_player_stat = function(player, stat, value)
	local stats = PyuTest.get_player_stats(player)
	stats[stat] = value
	PyuTest.save_player_stats(player, stats)
end

PyuTest.get_player_stat = function(player, stat)
	local stats = PyuTest.get_player_stats(player)
	return stats[stat]
end

core.register_on_player_hpchange(function(player, hp_change, reason)
	local max_hp = player:get_properties().hp_max
	local current_hp = player:get_hp()
	local new_hp_change = hp_change

	if new_hp_change >= 0 then
		return new_hp_change
	end

	local whitelist = {
		"set_hp",
		"fall",
		"drown",
		"node_damage",
		"respawn"
	}

	for _, v in pairs(whitelist) do
		if reason.type == v then
			return new_hp_change
		end
	end

	if reason.type == "punch" then
		local obj = reason.object

		if obj and obj:is_player() then
			local attack = PyuTest.get_player_stat(obj, "attack")
			new_hp_change = new_hp_change * attack
		end
	end

	if current_hp > (max_hp / 4) then
		local defense = PyuTest.get_player_stat(player, "defense")
		new_hp_change = new_hp_change / defense
		new_hp_change = math.floor(new_hp_change + 0.5)
	end

	return new_hp_change
end, true)

core.register_on_joinplayer(function(player)
	if player == nil then return end

	-- This saves the default stats if none exist.
	PyuTest.save_player_stats(player, PyuTest.get_player_stats(player))
end)

core.register_chatcommand("setstat", {
	params = "<stat> <value> [<player>]",
	privs = {
		give = 1
	},
	description = "Set the value of PLAYER's player stat STAT to VALUE",
	func = function(name, param)
		local split = param:split(" ")
		local statname = split[1]
		local value = tonumber(split[2])
		local player = split[3] or name

		-- Stat value below 1 causes problems
		if value < 1 then
			value = 1
		end

		PyuTest.set_player_stat(core.get_player_by_name(player), statname, value)
		return true, string.format("Set stat %s value to %s", statname, tostring(value))
	end
})

core.register_chatcommand("getstat", {
	params = "<stat> [<player>]",
	description = "Gets the value of PLAYER's player stat: STAT",
	func = function(name, param)
		local split = param:split(" ")
		local statname = split[1]
		local player = split[2] or name
		local stat = PyuTest.get_player_stat(core.get_player_by_name(player), statname)
		return true, string.format("%s of %s: %s", statname, player, tostring(stat or 0))
	end
})
