package com.tiedup.remake.v2.furniture.client;

import java.io.InputStream;
import java.util.Map;
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;
import org.jetbrains.annotations.Nullable;

/**
 * Lazy-loading cache for parsed multi-armature furniture GLB data.
 *
 * <p>Loads .glb files via Minecraft's ResourceManager on first access and parses them
 * with {@link FurnitureGlbParser}. Thread-safe via {@link ConcurrentHashMap}.
 *
 * <p>Call {@link #clear()} on resource reload (e.g., F3+T) to invalidate stale entries.
 *
 * <p>This class is client-only and must never be referenced from server code.
 */
@OnlyIn(Dist.CLIENT)
public final class FurnitureGltfCache {

    private static final Logger LOGGER = LogManager.getLogger("FurnitureGltf");

    /**
     * Sentinel value stored in the cache when loading fails, to avoid retrying
     * broken resources on every frame.
     */
    private static final FurnitureGltfData FAILED_SENTINEL =
        new FurnitureGltfData(null, Map.of(), Map.of(), Map.of());

    private static final Map<ResourceLocation, FurnitureGltfData> CACHE =
        new ConcurrentHashMap<>();

    private FurnitureGltfCache() {}

    /**
     * Get parsed furniture GLB data for a resource, loading and parsing on first access.
     *
     * @param modelLocation resource location of the .glb file
     *                      (e.g., {@code tiedup:models/furniture/wooden_stocks.glb})
     * @return parsed {@link FurnitureGltfData}, or {@code null} if loading/parsing failed
     */
    @Nullable
    public static FurnitureGltfData get(ResourceLocation modelLocation) {
        FurnitureGltfData cached = CACHE.computeIfAbsent(
            modelLocation,
            FurnitureGltfCache::load
        );
        return cached == FAILED_SENTINEL ? null : cached;
    }

    /**
     * Load and parse a furniture GLB from the resource manager.
     *
     * @return parsed data, or the {@link #FAILED_SENTINEL} on failure
     */
    private static FurnitureGltfData load(ResourceLocation loc) {
        try {
            Resource resource = Minecraft.getInstance()
                .getResourceManager()
                .getResource(loc)
                .orElse(null);
            if (resource == null) {
                LOGGER.error("[FurnitureGltf] Resource not found: {}", loc);
                return FAILED_SENTINEL;
            }

            try (InputStream is = resource.open()) {
                FurnitureGltfData data = FurnitureGlbParser.parse(
                    is,
                    loc.toString()
                );
                LOGGER.debug("[FurnitureGltf] Cached: {}", loc);
                return data;
            }
        } catch (Exception e) {
            LOGGER.error(
                "[FurnitureGltf] Failed to load furniture GLB: {}",
                loc,
                e
            );
            return FAILED_SENTINEL;
        }
    }

    /**
     * Clear all cached data. Call on resource reload (F3+T) or dimension change.
     */
    public static void clear() {
        int size = CACHE.size();
        CACHE.clear();
        if (size > 0) {
            LOGGER.info("[FurnitureGltf] Cache cleared ({} entries)", size);
        }
    }
}
