local wea = worldeditadditions
local wea_c = worldeditadditions_core
local Vector3 = wea_c.Vector3

local function parse_scale_component(val)
	local result = tonumber(val)
	if result then return true, result end
	if string.find(val, "/")  then
		local parts = wea_c.split(val, "/", true)
		local a = tonumber(parts[1])
		local b = tonumber(parts[2])
		if not b then return false, "Invalid number after the forward slash in scale component." end
		if not a then return false, "Invalid number before the forward slash in scale component." end
		return true, a / b
	end
	if string.find(val, "%%") then
		local part = tonumber(string.sub(val, 1, -2))
		if not part then return false, "We thought a scale component was a percentage, but failed to parse percentage as number." end
		return true, part / 100
	end
	return false, "Failed to parse scale component (unrecognised format - we support things like '3', '0.5', '1/10', or '33%' without quotes)."
end

-- ███████  ██████  █████  ██      ███████
-- ██      ██      ██   ██ ██      ██
-- ███████ ██      ███████ ██      █████
--      ██ ██      ██   ██ ██      ██
-- ███████  ██████ ██   ██ ███████ ███████
wea_c.register_command("scale", {
	params = "<axis> <scale_factor> | <factor_x> [<factor_y> <factor_z> [<anchor_x> <anchor_y> <anchor_z>]]",
	description = "Combined scale up / down. Takes either an axis name + a scale factor (e.g. y 3 or -z 2; negative values swap the anchor point for the scale operation), or 3 scale factor values for x, y, and z respectively. In the latter mode, a set of anchors can also be specified, which indicate which size the scale operation should be anchored to.",
	privs = { worldedit = true },
	require_pos = 2,
	parse = function(params_text)
		if not params_text then params_text = "" end
		
		local parts = wea_c.split_shell(params_text)
		
		local scale = Vector3.new(1, 1, 1)
		local anchor = Vector3.new(1, 1, 1)
		
		if #parts == 2 then
			if not (parts[1] == "x" or parts[1] == "y" or parts[1] == "z"
				or parts[1] == "-x" or parts[1] == "-y" or parts[1] == "-z") then
				return false, "Error: Got 2 arguments, but the first doesn't look like the name of an axis."
			end
			local axis = parts[1]
			local success, factor = parse_scale_component(parts[2])
			if not success then return success, "Error: Invalid scale factor. Details: "..factor end
			
			if axis:sub(1, 1) == "-" then
				axis = axis:sub(2, 2)
				anchor[axis] = -1
			end
			-- BUG: POTENTIAL BUG HERE
			scale[axis] = factor
		elseif #parts >= 3 then
			local success, val = parse_scale_component(parts[1])
			if not success then return false, "Error: x axis scale factor wasn't a number. Details: "..val end
			scale.x = val
			
			success, val = parse_scale_component(parts[2])
			if not success then return false, "Error: y axis scale factor wasn't a number. Details: "..val end
			scale.y = val
			
			success, val = parse_scale_component(parts[3])
			if not success then return false, "Error: z axis scale factor wasn't a number. Details: "..val end
			scale.z = val
		else
			local success, val = parse_scale_component(parts[1])
			if not success then
				return false, "Error: scale factor wasn't a number. Details: "..val
			end
			scale.x = val
			scale.y = val
			scale.z = val
		end
		
		if #parts == 6 then
			local val = tonumber(parts[4])
			if not val then return false, "Error: x axis anchor wasn't a number." end
			anchor.x = val
			val = tonumber(parts[5])
			if not val then return false, "Error: y axis anchor wasn't a number." end
			anchor.y = val
			val = tonumber(parts[6])
			if not val then return false, "Error: z axis anchor wasn't a number." end
			anchor.z = val
		end
		
		if scale.x == 0 then return false, "Error: x scale factor was 0" end
		if scale.y == 0 then return false, "Error: y scale factor was 0" end
		if scale.z == 0 then return false, "Error: z scale factor was 0" end
		
		if anchor.x == 0 then return false, "Error: x axis anchor was 0" end
		if anchor.y == 0 then return false, "Error: y axis anchor was 0" end
		if anchor.z == 0 then return false, "Error: z axis anchor was 0" end
		
		return true, scale, anchor
	end,
	nodes_needed = function(name, scale, anchor)
		local volume = worldedit.volume(worldedit.pos1[name], worldedit.pos2[name])
		local factor = math.ceil(math.abs(scale.x))
			* math.ceil(math.abs(scale.y))
			* math.ceil(math.abs(scale.z))
		return volume * factor
	end,
	func = function(name, scale, anchor)
		
		local start_time = wea_c.get_ms_time()
		
		local pos1, pos2 = Vector3.sort(worldedit.pos1[name], worldedit.pos2[name])
		
		local success, stats = wea.scale(
			pos1, pos2,
			scale, anchor
		)
		if not success then return success, stats end
		
		wea_c.pos.set1(name, stats.pos1)
		wea_c.pos.set2(name, stats.pos2)
		-- worldedit.pos1[name] = stats.pos1
		-- worldedit.pos2[name] = stats.pos2
		-- worldedit.marker_update(name)
		
		local time_taken = wea_c.get_ms_time() - start_time
		
		
		minetest.log("action", name.." used //scale at "..pos1.." - "..pos2..", updating "..stats.updated.." nodes in "..time_taken.."s")
		return true, stats.updated.." nodes updated in " .. wea_c.format.human_time(time_taken)
	end
})
