package com.tiedup.remake.worldgen;

import java.util.List;
import java.util.Map;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;

/**
 * Weighted random block selection with named condition variants.
 *
 * <p>Each palette maps condition names (e.g. "default", "bottom_row", "edge",
 * "corner", "cap") to a list of weighted block state entries. When a block
 * is requested for a condition that has no entries, falls back to "default".</p>
 */
public final class BlockPalette {

    /**
     * A single block state with its selection weight.
     *
     * @param state  the block state to place
     * @param weight relative weight (higher = more likely)
     */
    public record WeightedEntry(BlockState state, float weight) {}

    private final Map<String, List<WeightedEntry>> variants;

    /**
     * @param variants condition name to weighted entries map (defensively copied)
     */
    public BlockPalette(Map<String, List<WeightedEntry>> variants) {
        this.variants = Map.copyOf(variants);
    }

    /**
     * Pick a random block state for the given condition.
     * Falls back to "default" if the condition has no entries.
     *
     * @param random    the random source
     * @param condition the condition name (e.g. "default", "bottom_row")
     * @return a randomly selected block state
     */
    public BlockState pick(RandomSource random, String condition) {
        List<WeightedEntry> entries = variants.getOrDefault(
            condition, variants.get("default")
        );
        if (entries == null || entries.isEmpty()) {
            // Should never happen if parsed correctly -- safety fallback
            return Blocks.STONE.defaultBlockState();
        }

        float totalWeight = 0;
        for (WeightedEntry e : entries) {
            totalWeight += e.weight();
        }

        float roll = random.nextFloat() * totalWeight;
        float cumulative = 0;
        for (WeightedEntry e : entries) {
            cumulative += e.weight();
            if (roll < cumulative) return e.state();
        }

        // Floating-point edge case fallback
        return entries.get(entries.size() - 1).state();
    }

    /**
     * @return unmodifiable map of all condition variants
     */
    public Map<String, List<WeightedEntry>> variants() {
        return variants;
    }
}
