package top.r3944realms.lib39.datagen.provider;

import com.google.gson.JsonObject;
import net.minecraft.data.CachedOutput;
import net.minecraft.data.DataProvider;
import net.minecraft.data.PackOutput;
import net.minecraft.data.PackOutput.Target;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.Enchantment;
import net.minecraft.world.level.block.Block;
import org.jetbrains.annotations.NotNull;

import java.nio.file.Path;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;

/**
 * The type Language provider.
 */
public abstract class LanguageProvider implements DataProvider {
    private final Map<String, String> data = new TreeMap<>();
    private final PackOutput output;
    private final String modid;
    private final String locale;

    /**
     * Instantiates a new Language provider.
     *
     * @param output the output
     * @param modid  the modid
     * @param locale the locale
     */
    public LanguageProvider(PackOutput output, String modid, String locale) {
        this.output = output;
        this.modid = modid;
        this.locale = locale;
    }

    /**
     * Add translations.
     */
    protected abstract void addTranslations();

    public @NotNull CompletableFuture<?> run(@NotNull CachedOutput cache) {
        this.addTranslations();
        return !this.data.isEmpty() ? this.save(cache, this.output.getOutputFolder(Target.RESOURCE_PACK).resolve(this.modid).resolve("lang").resolve(this.locale + ".json")) : CompletableFuture.allOf();
    }

    public @NotNull String getName() {
        return "Languages: " + this.locale;
    }

    private @NotNull CompletableFuture<?> save(CachedOutput cache, Path target) {
        JsonObject json = new JsonObject();
        Objects.requireNonNull(json);
        this.data.forEach(json::addProperty);
        return DataProvider.saveStable(cache, json, target);
    }

    /**
     * Add block.
     *
     * @param key  the key
     * @param name the name
     */
    public void addBlock(@NotNull Supplier<? extends Block> key, String name) {
        this.add(key.get(), name);
    }

    /**
     * Add.
     *
     * @param key  the key
     * @param name the name
     */
    public void add(@NotNull Block key, String name) {
        this.add(key.getDescriptionId(), name);
    }

    /**
     * Add item.
     *
     * @param key  the key
     * @param name the name
     */
    public void addItem(@NotNull Supplier<? extends Item> key, String name) {
        this.add(key.get(), name);
    }

    /**
     * Add.
     *
     * @param key  the key
     * @param name the name
     */
    public void add(@NotNull Item key, String name) {
        this.add(key.getDescriptionId(), name);
    }

    /**
     * Add item stack.
     *
     * @param key  the key
     * @param name the name
     */
    public void addItemStack(@NotNull Supplier<ItemStack> key, String name) {
        this.add(key.get(), name);
    }

    /**
     * Add.
     *
     * @param key  the key
     * @param name the name
     */
    public void add(@NotNull ItemStack key, String name) {
        this.add(key.getDescriptionId(), name);
    }

    /**
     * Add enchantment.
     *
     * @param key  the key
     * @param name the name
     */
    public void addEnchantment(@NotNull Supplier<? extends Enchantment> key, String name) {
        this.add(key.get(), name);
    }

    /**
     * Add.
     *
     * @param key  the key
     * @param name the name
     */
    public void add(@NotNull Enchantment key, String name) {
        this.add(key.getDescriptionId(), name);
    }

    /**
     * Add effect.
     *
     * @param key  the key
     * @param name the name
     */
    public void addEffect(@NotNull Supplier<? extends MobEffect> key, String name) {
        this.add(key.get(), name);
    }

    /**
     * Add.
     *
     * @param key  the key
     * @param name the name
     */
    public void add(@NotNull MobEffect key, String name) {
        this.add(key.getDescriptionId(), name);
    }

    /**
     * Add entity type.
     *
     * @param key  the key
     * @param name the name
     */
    public void addEntityType(@NotNull Supplier<? extends EntityType<?>> key, String name) {
        this.add(key.get(), name);
    }

    /**
     * Add.
     *
     * @param key  the key
     * @param name the name
     */
    public void add(@NotNull EntityType<?> key, String name) {
        this.add(key.getDescriptionId(), name);
    }

    /**
     * Add.
     *
     * @param key   the key
     * @param value the value
     */
    public void add(String key, String value) {
        if (this.data.put(key, value) != null) {
            throw new IllegalStateException("Duplicate translation key " + key);
        }
    }
}