package pokefenn.totemic.apiimpl.registry;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import pokefenn.totemic.api.TotemicAPI;
import pokefenn.totemic.api.ceremony.Ceremony;
import pokefenn.totemic.api.music.MusicInstrument;
import pokefenn.totemic.api.registry.RegistryAPI;
import pokefenn.totemic.api.registry.TotemicRegisterEvent;
import pokefenn.totemic.api.totem.TotemEffect;

public enum RegistryApiImpl implements RegistryAPI {
    INSTANCE;

    private final Map<ResourceLocation, MusicInstrument> instruments = new LinkedHashMap<>();
    private final Map<ResourceLocation, TotemEffect> totemEffects = new LinkedHashMap<>();
    private final Map<ResourceLocation, Ceremony> ceremonies = new LinkedHashMap<>();

    private Map<List<MusicInstrument>, Ceremony> selectorsToCeremonyMap = null;

    @Override
    public Map<ResourceLocation, MusicInstrument> instruments() {
        return Collections.unmodifiableMap(instruments);
    }

    @Override
    public Map<ResourceLocation, TotemEffect> totemEffects() {
        return Collections.unmodifiableMap(totemEffects);
    }

    @Override
    public Map<ResourceLocation, Ceremony> ceremonies() {
        return Collections.unmodifiableMap(ceremonies);
    }

    public Map<List<MusicInstrument>, Ceremony> getSelectorsToCeremonyMap() {
        return selectorsToCeremonyMap;
    }

    private <T> void fireRegistryEvent(Class<T> type, Map<ResourceLocation, T> registry, Function<T, ResourceLocation> nameFunc) {
        FMLJavaModLoadingContext.get().getModEventBus().post(new TotemicRegisterEvent<>(type, object -> {
            Objects.requireNonNull(object);
            ResourceLocation name = nameFunc.apply(object);
            if(registry.containsKey(name))
                throw new IllegalArgumentException("The " + type.getSimpleName() + " object \"" + name + "\" has already been registered");
            registry.put(name, object);
        }));
    }

    public void registerInstruments() {
        fireRegistryEvent(MusicInstrument.class, instruments, MusicInstrument::getRegistryName);
    }

    public void registerTotemEffects() {
        fireRegistryEvent(TotemEffect.class, totemEffects, TotemEffect::getRegistryName);
    }

    public void registerCeremonies() {
        fireRegistryEvent(Ceremony.class, ceremonies, Ceremony::getRegistryName);
        computeSelectorsToCeremonyMap();
    }

    private void computeSelectorsToCeremonyMap() {
        //This will throw an exception if two different Ceremonies happen to have the same selectors.
        //Note that this check is not sufficient if MIN_SELECTORS != MAX_SELECTORS. In this case, we would have
        //to check for prefix-freeness. So we assume MIN_SELECTORS == MAX_SELECTORS here.
        selectorsToCeremonyMap = TotemicAPI.get().registry().ceremonies().values().stream()
                .collect(Collectors.toUnmodifiableMap(Ceremony::getSelectors, Function.identity()));
    }
}

@@ -370,39 +370,53 @@
 ort 
-pokefenn.totemic.api.TotemicAPI
+net.minecraftforge.fml.loading.FMLEnvironment
 ;%0Aim
@@ -3061,36 +3061,8 @@
 p = 
-TotemicAPI.get().registry().
 cere
@@ -3067,18 +3067,16 @@
 remonies
-()
 .values(
@@ -3186,16 +3186,570 @@
 ity()));
+%0A%0A        if(!FMLEnvironment.production) %7B%0A            //Check for unregistered music instruments, to prevent subtle issues.%0A            ceremonies.values().stream()%0A                    .flatMap(cer -%3E cer.getSelectors().stream())%0A                    .filter(instr -%3E !instruments.containsKey(instr.getRegistryName()))%0A                    .findAny()%0A                    .ifPresent(instr -%3E %7B%0A                        throw new RuntimeException(%22Music instrument %22 + instr.getRegistryName() + %22 has not been registered!%22);%0A                    %7D);%0A        %7D
 %0A    %7D%0A%7D

Add check for unregistered music instruments (in dev environment only)