/*
 * 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.JsonObject;
import com.google.gson.JsonParseException;
import io.zershyan.sccore.animation.data.AnimationData;
import io.zershyan.sccore.animation.data.GenericAnimationData;
import io.zershyan.sccore.animation.data.util.AnimJson;
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.GsonHelper;
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 AnimationDataManager extends SimpleJsonResourceReloadListener {
    public static final AnimationDataManager INSTANCE = new AnimationDataManager();
    public static final Map<ResourceLocation, GenericAnimationData> ANIMATIONS = new LinkedHashMap<>();
    private AnimationDataManager() {
        super(new GsonBuilder()
                .setPrettyPrinting()
                .disableHtmlEscaping()
                .create(), "ac_animations");
    }

    @Override
    protected void apply(@NotNull Map<ResourceLocation, JsonElement> resources,
                         @NotNull ResourceManager resourceManager,
                         @NotNull ProfilerFiller profiler) {
        ANIMATIONS.clear();
        AnimationCore.LOGGER.info("Loading animations 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(".anim.json")) {
                                    ResourceLocation rl = new ResourceLocation(namespace,
                                            path.substring("ac_animations/".length(), path.length() - ".json".length()));

                                    JsonElement el = resources.get(rl);
                                    if (el != null) {
                                        rl = new ResourceLocation(namespace,
                                                path.substring("ac_animations/".length(), path.length() - ".anim.json".length()));
                                        sorted.put(rl, el);
                                    }
                                }
                            }
                    )
            );
        });

        int loadedCount = 0;
        for (Map.Entry<ResourceLocation, JsonElement> entry : sorted.entrySet()) {
            ResourceLocation animKey = entry.getKey();

            try {
                JsonObject json = GsonHelper.convertToJsonObject(entry.getValue(), "animation");

                // Parse animation using existing AnimJson.Reader
                AnimJson.Reader animReader = AnimJson.Reader.stream(json);
                GenericAnimationData anim = animReader.parse();

                // Ensure the key matches
                if (!anim.getKey().equals(animKey)) {
                    AnimationCore.LOGGER.warn("Animation key mismatch: file={}, expected={}, actual={}",
                            entry.getKey(), animKey, anim.getKey());
                    anim = anim.withName(animKey.getPath()); // Create a copy with correct key if possible
                }

                registerAnimation(animKey, anim);
                loadedCount++;
                AnimationCore.LOGGER.debug("Loaded animation: {} -> {}", animKey, anim.getName());

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

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

    public static void registerAnimation(ResourceLocation key, GenericAnimationData animation) {
        ANIMATIONS.put(key, animation);
    }
}
