--[[ This mod is basically a compromise solution
for a long-known bug.

It checks if Luanti is running with the recommended
player movement settings. If the player has set any of the
relevant movement settings to a non-default value, that will
take preference over the game settings, which will break
this game’s vision somewhat, since the levels are carefully
designed to work with the game-provided movement settings.

Since there apparently is no way for Lazarr! to force-set
the movement settings without some arcane hackery, this mod
will just check the values and display a warning if a
deviation has been detected.
(This is important because it is very hard for a player
to realize otherwise they're playing Lazarr! with the
"wrong" physics.)

The player is then given a choice to either return to
Luanti and fix the problem or to ignore it and
continue playing.
Both a dialog message and a chat message will be displayed.

TODO: Find a non-hacky (!) way for Lazarr! to force player-movement
settings, then remove this mod.
]]

lzr_check_movement_settings = {}

local S = minetest.get_translator("lzr_check_movement_settings")
local FS = function(...) return minetest.formspec_escape(S(...)) end
local F = minetest.formspec_escape

-- Threshold for floating-point equality check
local EPSILON = 0.0001

-- This is the list of settings that needed to be checked, and their
-- expected value.
-- IMPORTANT: This MUST be equal to minetest.conf in this game's root directory!
local settings_to_check = {
	movement_speed_walk = 4.0,
	movement_speed_crouch = 1.35,
	movement_speed_climb = 3.0,
	movement_speed_jump = 6.5,
	movement_gravity = 9.81,
	movement_acceleration_air = 2.0,
	movement_acceleration_default = 3.0,
	movement_liquid_fluidity = 1.0,
	movement_liquid_fluidity_smooth = 0.5,
	movement_liquid_sink = 10.0,
}

local check_settings = function()
	local invalid_settings = {}
	for key, expected_value in pairs(settings_to_check) do
		local actual_value = tonumber(minetest.settings:get(key))
		if actual_value then
			-- Floating-point equality check with tolerance
			if math.abs(expected_value - actual_value) > EPSILON then
				table.insert(invalid_settings, key)
			end
		end
	end
	return invalid_settings
end

local invalid_settings = check_settings()

local registered_on_dismiss_warnings = {}
lzr_check_movement_settings.register_on_dismiss_warning = function(callback)
	table.insert(registered_on_dismiss_warnings, callback)
end

local STR_WARNING_1 = S("WARNING: The player movement settings are not at the recommended values for Lazarr! The physics might not work as intended!")
local STR_WARNING_2 = S("Please exit the game and reset the following Luanti settings to their default value:")
--~ list separator for list of invalid player movement settings
local STR_INVALID_SETTINGS = table.concat(invalid_settings, S(", "))

local disconnect = function(player)
	minetest.log("action", "[lzr_check_movement_settings] "..player:get_player_name().." chose to leave the game")
	minetest.disconnect_player(player:get_player_name(), S("You quit. Remember, Lazarr! expects the following Luanti settings to be reset to the default value: @1", STR_INVALID_SETTINGS))
end

local show_dialog = function(player_name)
	local form = "formspec_version[7]size[10,5]"..
		"textarea[1,0.8;8,2.5;;;"..F(STR_WARNING_1).."\n"..F(STR_WARNING_2).."\n"..STR_INVALID_SETTINGS.."]"..
		"button_exit[1,3.5;3,0.8;exit;"..FS("Exit game").."]"..
		"button_exit[5.5,3.5;3,0.8;play;"..FS("Continue playing anyway").."]"
	minetest.show_formspec(player_name, "lzr_check_movement_settings:movement_settings_warning", form)
end

minetest.register_on_player_receive_fields(function(player, formname, fields)
	if formname ~= "lzr_check_movement_settings:movement_settings_warning" then
		return
	end
	if fields.exit then
		disconnect(player)
	elseif fields.play or fields.quit then
		minetest.log("action", "[lzr_check_movement_settings] "..player:get_player_name().." chose to play game despite the non-default movement settings")
		-- Call 'dismiss warning' callbacks
		for i=1, #registered_on_dismiss_warnings do
			registered_on_dismiss_warnings[i](player)
		end
	end
end)

minetest.register_on_joinplayer(function(player)
	local pname = player:get_player_name()
	if #invalid_settings == 0 then
		return
	end

	minetest.log("action", "[lzr_check_movement_settings] Non-default movement settings detected, game physics might be degraded")
	-- Chat messages
	local function msg(text)
		minetest.chat_send_player(pname, minetest.colorize("#FF8000", text))
	end
	msg(STR_WARNING_1)
	msg(STR_WARNING_2)
	msg(STR_INVALID_SETTINGS)

	-- Additional, a dialog
	show_dialog(pname)
end)

-- Expose checker function publicly
lzr_check_movement_settings.check_movement_settings = function()
	local t = check_settings()
	if #t == 0 then
		return true
	else
		return false
	end
end
