package net.minecraft.util.datafix.fixes;

import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gson.JsonElement;
import com.mojang.datafixers.DataFix;
import com.mojang.datafixers.TypeRewriteRule;
import com.mojang.datafixers.schemas.Schema;
import com.mojang.datafixers.types.Type;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Dynamic;
import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.JsonOps;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import net.minecraft.Util;
import net.minecraft.util.LenientJsonParser;

public class LevelDataGeneratorOptionsFix extends DataFix {
    static final Map<String, String> MAP = Util.make(Maps.newHashMap(), map -> {
        map.put("0", "minecraft:ocean");
        map.put("1", "minecraft:plains");
        map.put("2", "minecraft:desert");
        map.put("3", "minecraft:mountains");
        map.put("4", "minecraft:forest");
        map.put("5", "minecraft:taiga");
        map.put("6", "minecraft:swamp");
        map.put("7", "minecraft:river");
        map.put("8", "minecraft:nether");
        map.put("9", "minecraft:the_end");
        map.put("10", "minecraft:frozen_ocean");
        map.put("11", "minecraft:frozen_river");
        map.put("12", "minecraft:snowy_tundra");
        map.put("13", "minecraft:snowy_mountains");
        map.put("14", "minecraft:mushroom_fields");
        map.put("15", "minecraft:mushroom_field_shore");
        map.put("16", "minecraft:beach");
        map.put("17", "minecraft:desert_hills");
        map.put("18", "minecraft:wooded_hills");
        map.put("19", "minecraft:taiga_hills");
        map.put("20", "minecraft:mountain_edge");
        map.put("21", "minecraft:jungle");
        map.put("22", "minecraft:jungle_hills");
        map.put("23", "minecraft:jungle_edge");
        map.put("24", "minecraft:deep_ocean");
        map.put("25", "minecraft:stone_shore");
        map.put("26", "minecraft:snowy_beach");
        map.put("27", "minecraft:birch_forest");
        map.put("28", "minecraft:birch_forest_hills");
        map.put("29", "minecraft:dark_forest");
        map.put("30", "minecraft:snowy_taiga");
        map.put("31", "minecraft:snowy_taiga_hills");
        map.put("32", "minecraft:giant_tree_taiga");
        map.put("33", "minecraft:giant_tree_taiga_hills");
        map.put("34", "minecraft:wooded_mountains");
        map.put("35", "minecraft:savanna");
        map.put("36", "minecraft:savanna_plateau");
        map.put("37", "minecraft:badlands");
        map.put("38", "minecraft:wooded_badlands_plateau");
        map.put("39", "minecraft:badlands_plateau");
        map.put("40", "minecraft:small_end_islands");
        map.put("41", "minecraft:end_midlands");
        map.put("42", "minecraft:end_highlands");
        map.put("43", "minecraft:end_barrens");
        map.put("44", "minecraft:warm_ocean");
        map.put("45", "minecraft:lukewarm_ocean");
        map.put("46", "minecraft:cold_ocean");
        map.put("47", "minecraft:deep_warm_ocean");
        map.put("48", "minecraft:deep_lukewarm_ocean");
        map.put("49", "minecraft:deep_cold_ocean");
        map.put("50", "minecraft:deep_frozen_ocean");
        map.put("127", "minecraft:the_void");
        map.put("129", "minecraft:sunflower_plains");
        map.put("130", "minecraft:desert_lakes");
        map.put("131", "minecraft:gravelly_mountains");
        map.put("132", "minecraft:flower_forest");
        map.put("133", "minecraft:taiga_mountains");
        map.put("134", "minecraft:swamp_hills");
        map.put("140", "minecraft:ice_spikes");
        map.put("149", "minecraft:modified_jungle");
        map.put("151", "minecraft:modified_jungle_edge");
        map.put("155", "minecraft:tall_birch_forest");
        map.put("156", "minecraft:tall_birch_hills");
        map.put("157", "minecraft:dark_forest_hills");
        map.put("158", "minecraft:snowy_taiga_mountains");
        map.put("160", "minecraft:giant_spruce_taiga");
        map.put("161", "minecraft:giant_spruce_taiga_hills");
        map.put("162", "minecraft:modified_gravelly_mountains");
        map.put("163", "minecraft:shattered_savanna");
        map.put("164", "minecraft:shattered_savanna_plateau");
        map.put("165", "minecraft:eroded_badlands");
        map.put("166", "minecraft:modified_wooded_badlands_plateau");
        map.put("167", "minecraft:modified_badlands_plateau");
    });
    public static final String GENERATOR_OPTIONS = "generatorOptions";

    public LevelDataGeneratorOptionsFix(Schema outputSchema, boolean changesType) {
        super(outputSchema, changesType);
    }

    @Override
    protected TypeRewriteRule makeRule() {
        Type<?> type = this.getOutputSchema().getType(References.LEVEL);
        return this.fixTypeEverywhereTyped(
            "LevelDataGeneratorOptionsFix",
            this.getInputSchema().getType(References.LEVEL),
            type,
            typed -> Util.writeAndReadTypedOrThrow(typed, type, dynamic -> {
                Optional<String> optional = dynamic.get("generatorOptions").asString().result();
                if ("flat".equalsIgnoreCase(dynamic.get("generatorName").asString(""))) {
                    String string = optional.orElse("");
                    return dynamic.set("generatorOptions", convert(string, dynamic.getOps()));
                } else if ("buffet".equalsIgnoreCase(dynamic.get("generatorName").asString("")) && optional.isPresent()) {
                    JsonElement jsonElement = LenientJsonParser.parse(optional.get());
                    return dynamic.set("generatorOptions", new Dynamic<>(JsonOps.INSTANCE, jsonElement).convert(dynamic.getOps()));
                } else {
                    return dynamic;
                }
            })
        );
    }

    private static <T> Dynamic<T> convert(String generatorOptions, DynamicOps<T> ops) {
        Iterator<String> iterator = Splitter.on(';').split(generatorOptions).iterator();
        String string = "minecraft:plains";
        Map<String, Map<String, String>> map = Maps.newHashMap();
        List<Pair<Integer, String>> layersInfoFromString;
        if (!generatorOptions.isEmpty() && iterator.hasNext()) {
            layersInfoFromString = getLayersInfoFromString(iterator.next());
            if (!layersInfoFromString.isEmpty()) {
                if (iterator.hasNext()) {
                    string = MAP.getOrDefault(iterator.next(), "minecraft:plains");
                }

                if (iterator.hasNext()) {
                    String[] parts = iterator.next().toLowerCase(Locale.ROOT).split(",");

                    for (String string1 : parts) {
                        String[] parts1 = string1.split("\\(", 2);
                        if (!parts1[0].isEmpty()) {
                            map.put(parts1[0], Maps.newHashMap());
                            if (parts1.length > 1 && parts1[1].endsWith(")") && parts1[1].length() > 1) {
                                String[] parts2 = parts1[1].substring(0, parts1[1].length() - 1).split(" ");

                                for (String string2 : parts2) {
                                    String[] parts3 = string2.split("=", 2);
                                    if (parts3.length == 2) {
                                        map.get(parts1[0]).put(parts3[0], parts3[1]);
                                    }
                                }
                            }
                        }
                    }
                } else {
                    map.put("village", Maps.newHashMap());
                }
            }
        } else {
            layersInfoFromString = Lists.newArrayList();
            layersInfoFromString.add(Pair.of(1, "minecraft:bedrock"));
            layersInfoFromString.add(Pair.of(2, "minecraft:dirt"));
            layersInfoFromString.add(Pair.of(1, "minecraft:grass_block"));
            map.put("village", Maps.newHashMap());
        }

        T object = ops.createList(
            layersInfoFromString.stream()
                .map(
                    pair -> ops.createMap(
                        ImmutableMap.of(
                            ops.createString("height"), ops.createInt(pair.getFirst()), ops.createString("block"), ops.createString(pair.getSecond())
                        )
                    )
                )
        );
        T object1 = ops.createMap(
            map.entrySet()
                .stream()
                .map(
                    entry -> Pair.of(
                        ops.createString(entry.getKey().toLowerCase(Locale.ROOT)),
                        ops.createMap(
                            entry.getValue()
                                .entrySet()
                                .stream()
                                .map(entry1 -> Pair.of(ops.createString(entry1.getKey()), ops.createString(entry1.getValue())))
                                .collect(Collectors.toMap(Pair::getFirst, Pair::getSecond))
                        )
                    )
                )
                .collect(Collectors.toMap(Pair::getFirst, Pair::getSecond))
        );
        return new Dynamic<>(
            ops,
            ops.createMap(
                ImmutableMap.of(
                    ops.createString("layers"), object, ops.createString("biome"), ops.createString(string), ops.createString("structures"), object1
                )
            )
        );
    }

    @Nullable
    private static Pair<Integer, String> getLayerInfoFromString(String layer) {
        String[] parts = layer.split("\\*", 2);
        int i;
        if (parts.length == 2) {
            try {
                i = Integer.parseInt(parts[0]);
            } catch (NumberFormatException var4) {
                return null;
            }
        } else {
            i = 1;
        }

        String string = parts[parts.length - 1];
        return Pair.of(i, string);
    }

    private static List<Pair<Integer, String>> getLayersInfoFromString(String layers) {
        List<Pair<Integer, String>> list = Lists.newArrayList();
        String[] parts = layers.split(",");

        for (String string : parts) {
            Pair<Integer, String> layerInfoFromString = getLayerInfoFromString(string);
            if (layerInfoFromString == null) {
                return Collections.emptyList();
            }

            list.add(layerInfoFromString);
        }

        return list;
    }
}
