/*
 * Anim Core mod
 *  Copyright (C)  2026  LeisureTimeDock
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package top.leisuretimedock.animationcore.animation;

import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import io.zershyan.sccore.animation.data.util.AnimLayerJson;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.PackType;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener;
import net.minecraft.util.profiling.ProfilerFiller;
import org.jetbrains.annotations.NotNull;
import top.leisuretimedock.animationcore.AnimationCore;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

public class LayerDataManager extends SimpleJsonResourceReloadListener {
    public static final LayerDataManager INSTANCE = new LayerDataManager();
    public static final Map<ResourceLocation, Integer> LAYERS = new LinkedHashMap<>();

    private LayerDataManager() {
        super(new GsonBuilder()
                .setPrettyPrinting()
                .disableHtmlEscaping()
                .create(), "ac_animations");
    }

    @Override
    protected void apply(@NotNull Map<ResourceLocation, JsonElement> resources,
                         @NotNull ResourceManager resourceManager,
                         @NotNull ProfilerFiller profiler) {
        LAYERS.clear();
        AnimationCore.LOGGER.info("Loading layer configurations from data packs...");

        Map<ResourceLocation, JsonElement> sorted = new LinkedHashMap<>();

        // Sort resources by priority
        resourceManager.listPacks().forEach(packResources -> {
            Set<String> namespaces = packResources.getNamespaces(PackType.SERVER_DATA);
            namespaces.forEach(namespace ->
                    packResources.listResources(PackType.SERVER_DATA, namespace, "ac_animations",
                            (resourceLocation, inputStreamIoSupplier) -> {
                                String path = resourceLocation.getPath();
                                if (path.endsWith("animation.layer.json")) {
                                    ResourceLocation rl = new ResourceLocation(namespace, "animation.layer");

                                    JsonElement el = resources.get(rl);
                                    if (el != null) {
                                        rl = new ResourceLocation(namespace, "animation_layer");
                                        sorted.put(rl, el);
                                    }
                                }
                            }
                    )
            );
        });

        int loadedCount = 0;
        for (Map.Entry<ResourceLocation, JsonElement> entry : sorted.entrySet()) {
            try {
                Map<ResourceLocation, Integer> parsedLayers = getResourceLocationIntegerMap(entry);

                loadedCount += parsedLayers.size();
                AnimationCore.LOGGER.debug("Loaded {} layer configurations from {}",
                        parsedLayers.size(), entry.getKey().getNamespace());

            } catch (IllegalArgumentException | JsonParseException e) {
                AnimationCore.LOGGER.error("Parsing error loading layer configuration", e);
            }
        }

        AnimationCore.LOGGER.info("Loaded {} layer configurations from data packs", loadedCount);
    }

    private static @NotNull Map<ResourceLocation, Integer> getResourceLocationIntegerMap(Map.Entry<ResourceLocation, JsonElement> entry) {
        JsonElement json = entry.getValue();
        AnimLayerJson.Reader layerReader = AnimLayerJson.Reader.stream(json);
        Map<ResourceLocation, Integer> parsedLayers = layerReader.parse();

        // Merge layer configurations
        parsedLayers.forEach((layerKey, priority) -> {
            if (containsKey(layerKey)) {
                AnimationCore.LOGGER.debug("Overriding layer {} with priority {}", layerKey, priority);
            }
            registerLayer(layerKey, priority);
        });
        return parsedLayers;
    }

    public static void registerLayer(ResourceLocation key, int priority) {
        LAYERS.put(key, priority);
    }

    public static boolean containsKey(ResourceLocation key) {
        return LAYERS.containsKey(key);
    }
}
