class_name WorldGenerator

const CHUNK_SIZE: int = 16

static func generate_chunk(chunk_x: int, chunk_y: int, chunk_z: int, seed: int) -> PackedInt32Array:
	var data: PackedInt32Array = PackedInt32Array()
	data.resize(4096)

	var noise_surface: FastNoiseLite = FastNoiseLite.new()
	noise_surface.seed = seed
	noise_surface.noise_type = FastNoiseLite.TYPE_SIMPLEX_SMOOTH
	noise_surface.frequency = 0.015

	var noise_biome: FastNoiseLite = FastNoiseLite.new()
	noise_biome.seed = seed + 1337
	noise_biome.noise_type = FastNoiseLite.TYPE_SIMPLEX_SMOOTH
	noise_biome.frequency = 0.004

	var noise_detail: FastNoiseLite = FastNoiseLite.new()
	noise_detail.seed = seed + 42
	noise_detail.noise_type = FastNoiseLite.TYPE_SIMPLEX_SMOOTH
	noise_detail.frequency = 0.05

	var noise_wreck: FastNoiseLite = FastNoiseLite.new()
	noise_wreck.seed = seed + 999
	noise_wreck.noise_type = FastNoiseLite.TYPE_CELLULAR
	noise_wreck.frequency = 0.03

	for lx: int in range(CHUNK_SIZE):
		for lz: int in range(CHUNK_SIZE):
			var wx: int = chunk_x * CHUNK_SIZE + lx
			var wz: int = chunk_z * CHUNK_SIZE + lz

			var surface_val: float = noise_surface.get_noise_2d(float(wx), float(wz))
			var ground_height: int = int(-20.0 + surface_val * 20.0)

			var biome_val: float = noise_biome.get_noise_2d(float(wx), float(wz))
			var biome: int = _get_biome(biome_val, ground_height)

			var wreck_val: float = noise_wreck.get_noise_2d(float(wx), float(wz))
			var is_wreck_center: bool = wreck_val > 0.75

			for ly: int in range(CHUNK_SIZE):
				var wy: int = chunk_y * CHUNK_SIZE + ly
				var idx: int = lx + ly * CHUNK_SIZE + lz * 256

				data[idx] = _get_block_at(wy, ground_height, biome, wx, wz, lx, lz,
						is_wreck_center, noise_detail, seed)

	return data

static func _get_biome(biome_val: float, ground_height: int) -> int:
	if biome_val > 0.5:
		return 0
	elif biome_val > 0.0:
		return 1
	elif biome_val > -0.5:
		return 2
	else:
		return 3

static func _get_block_at(wy: int, ground_height: int, biome: int,
		wx: int, wz: int, lx: int, lz: int,
		is_wreck_center: bool, noise_detail: FastNoiseLite, seed: int) -> int:

	if wy <= -60:
		return BlockDatabase.BlockType.BEDROCK

	if wy < ground_height - 5:
		return BlockDatabase.BlockType.ROCK

	if wy < ground_height:
		return BlockDatabase.BlockType.SAND

	if wy == ground_height:
		return _surface_block(biome, wx, wz, noise_detail)

	if wy == ground_height + 1:
		return _decoration_block(biome, wx, wz, noise_detail, seed)

	if wy > ground_height + 1 and wy <= ground_height + 6:
		if biome == 1:
			var kelp_height: int = _kelp_height(wx, wz, seed)
			if wy <= ground_height + kelp_height:
				return BlockDatabase.BlockType.KELP

	if wy > 60:
		return BlockDatabase.BlockType.AIR

	if wy >= 58:
		var ice_noise: float = noise_detail.get_noise_2d(float(wx) * 0.5, float(wz) * 0.5)
		if ice_noise > 0.6:
			return BlockDatabase.BlockType.ICE
		return BlockDatabase.BlockType.WATER

	if wy > ground_height:
		if is_wreck_center and biome == 3:
			var rel_y: int = wy - ground_height - 1
			if rel_y >= 0 and rel_y < 3:
				var rel_x: int = (wx % 5 + 5) % 5
				var rel_z: int = (wz % 3 + 3) % 3
				if rel_x < 5 and rel_z < 3:
					if rel_y == 0 or rel_y == 2 or rel_x == 0 or rel_x == 4 or rel_z == 0 or rel_z == 2:
						return BlockDatabase.BlockType.WRECK_WOOD
		return BlockDatabase.BlockType.WATER

	return BlockDatabase.BlockType.WATER

static func _surface_block(biome: int, wx: int, wz: int, noise_detail: FastNoiseLite) -> int:
	match biome:
		0:
			return BlockDatabase.BlockType.SAND
		1:
			return BlockDatabase.BlockType.SAND
		2:
			return BlockDatabase.BlockType.ROCK
		3:
			return BlockDatabase.BlockType.SAND
		_:
			return BlockDatabase.BlockType.SAND

static func _decoration_block(biome: int, wx: int, wz: int, noise_detail: FastNoiseLite, seed: int) -> int:
	match biome:
		0:
			var coral_noise: float = noise_detail.get_noise_2d(float(wx + seed % 100), float(wz + seed % 100))
			if coral_noise > 0.4:
				if (wx + wz) % 2 == 0:
					return BlockDatabase.BlockType.CORAL_RED
				else:
					return BlockDatabase.BlockType.CORAL_BLUE
		_:
			pass
	return BlockDatabase.BlockType.WATER

static func _kelp_height(wx: int, wz: int, seed: int) -> int:
	var h: int = ((wx * 73856093) ^ (wz * 19349663) ^ seed) % 4
	return 3 + h
