package net.mcreator.customoregen.worldgen;

import net.mcreator.customoregen.CustomOreGenMod;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.tags.TagKey;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.Biomes;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.storage.ServerLevelData;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.event.level.LevelEvent;

import java.util.Set;

/**
 * Forces the world spawn point to a plains-like biome near the origin.
 *
 * <p>Because {@link LatitudeBiomeSource} places temperate biomes around Z=0, a plains
 * or forest biome is always available close to spawn. This handler runs once per server
 * lifetime when the overworld loads, scans a growing square around the origin and pins
 * the default spawn point to the first matching biome. The player therefore always
 * starts the game on open, buildable terrain instead of a swamp, mountain or ocean.</p>
 */
@EventBusSubscriber(modid = CustomOreGenMod.MODID)
public class LatitudeSpawnHandler {

	/** Biomes considered a good starting point (open, buildable temperate terrain). */
	private static final Set<ResourceKey<Biome>> SPAWN_BIOMES = Set.of(
			Biomes.PLAINS, Biomes.SUNFLOWER_PLAINS,
			Biomes.FOREST, Biomes.BIRCH_FOREST, Biomes.FLOWER_FOREST,
			Biomes.MEADOW, Biomes.CHERRY_GROVE
	);

	/** Maximum search radius (in blocks) around the origin. */
	private static final int MAX_RADIUS = 512;

	/** Step between sampled positions. */
	private static final int STEP = 8;

	private static volatile boolean initialized = false;

	@SubscribeEvent
	public static void onLevelLoad(LevelEvent.Load event) {
		if (initialized) {
			return;
		}
		if (!(event.getLevel() instanceof ServerLevel level)) {
			return;
		}
		if (level.dimension() != Level.OVERWORLD) {
			return;
		}

		initialized = true;

		if (!(level.getLevelData() instanceof ServerLevelData levelData)) {
			return;
		}

		BlockPos current = levelData.getSpawnPos();
		if (isSpawnBiome(level, current)) {
			return; // Already on a good biome, leave it alone.
		}

		BlockPos found = findSpawnBiome(level);
		if (found == null) {
			CustomOreGenMod.LOGGER.warn("Latitude: no suitable spawn biome found within {} blocks, keeping {}", MAX_RADIUS, current);
			return;
		}

		int y = level.getHeight(Heightmap.Types.WORLD_SURFACE_WG, found.getX(), found.getZ());
		BlockPos spawn = new BlockPos(found.getX(), y, found.getZ());
		level.setDefaultSpawnPos(spawn, 0.0f);
		CustomOreGenMod.LOGGER.info("Latitude: spawn point set to {} ({})", spawn,
				level.getBiome(spawn).unwrapKey().map(Object::toString).orElse("?"));
	}

	private static boolean isSpawnBiome(ServerLevel level, BlockPos pos) {
		Holder<Biome> biome = level.getBiome(pos);
		return biome.unwrapKey().map(SPAWN_BIOMES::contains).orElse(false);
	}

	private static BlockPos findSpawnBiome(ServerLevel level) {
		// Concentric square rings starting from the origin.
		for (int radius = 0; radius <= MAX_RADIUS; radius += STEP) {
			for (int x = -radius; x <= radius; x += STEP) {
				for (int z = -radius; z <= radius; z += STEP) {
					// Only scan the outer ring of each pass to avoid re-checking inner cells.
					if (Math.abs(x) != radius && Math.abs(z) != radius && radius != 0) {
						continue;
					}
					BlockPos pos = new BlockPos(x, 0, z);
					if (isSpawnBiome(level, pos)) {
						return pos;
					}
				}
			}
		}
		return null;
	}
}
