package net.mcreator.customoregen.worldgen;

import net.minecraft.core.Holder;
import net.minecraft.core.HolderGetter;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.Biomes;

import java.util.ArrayList;
import java.util.List;

/**
 * Latitude climate bands used by {@link LatitudeBiomeSource}.
 *
 * <p>The world is split along the Z axis (latitude) into climate bands:
 * the far north is frozen, the equator is temperate, and the far south is hot.
 * Surface biomes are selected from dedicated climate tags (so optional mods such
 * as Biomes O' Plenty are supported gracefully). Ocean and underground (cave) pools
 * are vanilla-only and resolved eagerly because those biomes always exist.</p>
 */
public enum BiomeBand {
	FROZEN(-1.0),
	COLD(-0.5),
	TEMPERATE(0.0),
	WARM(0.5),
	HOT(1.0);

	/** Mid-temperature of the band, in [-1.0, 1.0]. */
	public final double centerTemperature;

	BiomeBand(double centerTemperature) {
		this.centerTemperature = centerTemperature;
	}

	public static BiomeBand fromTemperature(double temperature) {
		if (temperature <= -0.7) return FROZEN;
		if (temperature <= -0.25) return COLD;
		if (temperature < 0.25) return TEMPERATE;
		if (temperature < 0.7) return WARM;
		return HOT;
	}

	/** Surface biome tag for this band (vanilla + optional Biomes O' Plenty). */
	public TagKey<Biome> surfaceTag() {
		switch (this) {
			case FROZEN:
			case COLD:
				return tag("latitude_cold_surface");
			case TEMPERATE:
				return tag("latitude_temperate_surface");
			case WARM:
			case HOT:
				return tag("latitude_hot_surface");
			default:
				return tag("latitude_temperate_surface");
		}
	}

	/**
	 * Vanilla surface biomes, used to declare {@code possibleBiomes} safely during worldgen
	 * data loading. The full (mod-aware) surface pool is resolved lazily from {@link #surfaceTag()}.
	 */
	public List<ResourceKey<Biome>> surfaceVanilla() {
		switch (this) {
			case FROZEN:
				return List.of(
						Biomes.SNOWY_PLAINS, Biomes.ICE_SPIKES, Biomes.SNOWY_TAIGA,
						Biomes.GROVE, Biomes.SNOWY_SLOPES, Biomes.JAGGED_PEAKS, Biomes.FROZEN_PEAKS
				);
			case COLD:
				return List.of(
						Biomes.TAIGA, Biomes.OLD_GROWTH_PINE_TAIGA, Biomes.OLD_GROWTH_SPRUCE_TAIGA,
						Biomes.WINDSWEPT_HILLS, Biomes.WINDSWEPT_FOREST, Biomes.WINDSWEPT_GRAVELLY_HILLS,
						Biomes.GROVE, Biomes.SNOWY_SLOPES
				);
			case TEMPERATE:
				return List.of(
						Biomes.PLAINS, Biomes.SUNFLOWER_PLAINS, Biomes.FOREST, Biomes.BIRCH_FOREST,
						Biomes.OLD_GROWTH_BIRCH_FOREST, Biomes.DARK_FOREST, Biomes.FLOWER_FOREST,
						Biomes.SWAMP, Biomes.MEADOW, Biomes.CHERRY_GROVE
				);
			case WARM:
				return List.of(
						Biomes.SAVANNA, Biomes.SAVANNA_PLATEAU, Biomes.WINDSWEPT_SAVANNA,
						Biomes.BIRCH_FOREST, Biomes.FOREST, Biomes.PLAINS, Biomes.MEADOW
				);
			case HOT:
				return List.of(
						Biomes.DESERT, Biomes.BADLANDS, Biomes.WOODED_BADLANDS, Biomes.ERODED_BADLANDS,
						Biomes.SAVANNA, Biomes.JUNGLE, Biomes.SPARSE_JUNGLE, Biomes.BAMBOO_JUNGLE,
						Biomes.MANGROVE_SWAMP
				);
			default:
				return List.of(Biomes.PLAINS);
		}
	}

	public List<ResourceKey<Biome>> ocean() {
		switch (this) {
			case FROZEN:
				return List.of(Biomes.FROZEN_OCEAN, Biomes.DEEP_FROZEN_OCEAN, Biomes.FROZEN_RIVER);
			case COLD:
				return List.of(Biomes.COLD_OCEAN, Biomes.DEEP_COLD_OCEAN);
			case TEMPERATE:
				return List.of(Biomes.OCEAN, Biomes.DEEP_OCEAN, Biomes.RIVER);
			case WARM:
				return List.of(Biomes.LUKEWARM_OCEAN, Biomes.DEEP_LUKEWARM_OCEAN);
			case HOT:
				return List.of(Biomes.WARM_OCEAN);
			default:
				return List.of(Biomes.OCEAN);
		}
	}

	/** Resolve a list of (possibly absent) biome keys into actual holders, skipping missing ones. */
	public static List<Holder<Biome>> resolve(HolderGetter<Biome> getter, List<ResourceKey<Biome>> keys) {
		List<Holder<Biome>> holders = new ArrayList<>();
		for (ResourceKey<Biome> key : keys) {
			getter.get(key).ifPresent(holders::add);
		}
		return holders;
	}

	private static TagKey<Biome> tag(String name) {
		return TagKey.create(Registries.BIOME, ResourceLocation.fromNamespaceAndPath("custom_ore_gen", name));
	}
}
