package com.tiedup.remake.client.gltf;

import java.io.InputStream;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.client.Minecraft;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.Resource;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 * Lazy-loading cache for parsed glTF data.
 *
 * <p>Loads .glb files via Minecraft's ResourceManager on first access.
 * Cache values are {@link Optional}: empty means a previous load attempt
 * failed and no retry will happen until {@link #clearCache()} is called.
 * This mirrors {@link com.tiedup.remake.v2.furniture.client.FurnitureGltfCache
 * FurnitureGltfCache}'s pattern so both caches have consistent semantics.</p>
 *
 * <p>Load is atomic via {@link Map#computeIfAbsent}: two concurrent first-misses
 * for the same resource will parse the GLB exactly once.</p>
 */
@OnlyIn(Dist.CLIENT)
public final class GltfCache {

    private static final Logger LOGGER = LogManager.getLogger("GltfPipeline");
    private static final Map<ResourceLocation, Optional<GltfData>> CACHE =
        new ConcurrentHashMap<>();

    private GltfCache() {}

    /**
     * Get parsed glTF data for a resource, loading it on first access.
     *
     * @param location resource location of the .glb file
     * @return parsed GltfData, or null if loading failed
     */
    public static GltfData get(ResourceLocation location) {
        return CACHE.computeIfAbsent(location, GltfCache::load).orElse(null);
    }

    private static Optional<GltfData> load(ResourceLocation location) {
        try {
            Resource resource = Minecraft.getInstance()
                .getResourceManager()
                .getResource(location)
                .orElse(null);
            if (resource == null) {
                LOGGER.error("[GltfPipeline] Resource not found: {}", location);
                return Optional.empty();
            }
            try (InputStream is = resource.open()) {
                GltfData data = GlbParser.parse(is, location.toString());
                return Optional.of(data);
            }
        } catch (Exception e) {
            LOGGER.error("[GltfPipeline] Failed to load GLB: {}", location, e);
            return Optional.empty();
        }
    }

    /** Clear all cached data (call on resource reload). */
    public static void clearCache() {
        CACHE.clear();
        LOGGER.info("[GltfPipeline] Cache cleared");
    }

    /** Initialize the cache (called during FMLClientSetupEvent). */
    public static void init() {
        LOGGER.info("[GltfPipeline] GltfCache initialized");
    }
}
