package com.tiedup.remake.v2.bondage.datadriven;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.Resource;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.server.packs.resources.SimplePreparableReloadListener;
import net.minecraft.util.profiling.ProfilerFiller;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 * Resource reload listener that scans {@code assets/<namespace>/tiedup_items/}
 * for JSON files and populates the {@link DataDrivenItemRegistry}.
 *
 * <p>Registered via {@link net.minecraftforge.client.event.RegisterClientReloadListenersEvent}
 * in {@link com.tiedup.remake.client.gltf.GltfClientSetup}.</p>
 *
 * <p>Follows the same pattern as {@link com.tiedup.remake.client.animation.context.ContextGlbRegistry}:
 * prepare phase is a no-op, apply phase scans + parses + atomic-swaps the registry.</p>
 */
public class DataDrivenItemReloadListener
    extends SimplePreparableReloadListener<Void>
{

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

    /** Resource directory containing item definition JSON files. */
    private static final String DIRECTORY = "tiedup_items";

    @Override
    protected Void prepare(
        ResourceManager resourceManager,
        ProfilerFiller profiler
    ) {
        // No preparation needed — parsing happens in apply phase
        return null;
    }

    @Override
    protected void apply(
        Void nothing,
        ResourceManager resourceManager,
        ProfilerFiller profiler
    ) {
        Map<ResourceLocation, DataDrivenItemDefinition> newDefs =
            new HashMap<>();

        Map<ResourceLocation, Resource> resources =
            resourceManager.listResources(DIRECTORY, loc ->
                loc.getPath().endsWith(".json")
            );

        int skipped = 0;

        for (Map.Entry<
            ResourceLocation,
            Resource
        > entry : resources.entrySet()) {
            ResourceLocation fileId = entry.getKey();
            Resource resource = entry.getValue();

            try (InputStream input = resource.open()) {
                DataDrivenItemDefinition def = DataDrivenItemParser.parse(
                    input,
                    fileId
                );

                if (def != null) {
                    // Check for duplicate IDs
                    if (newDefs.containsKey(def.id())) {
                        LOGGER.warn(
                            "[DataDrivenItems] Duplicate item ID '{}' from file '{}' — overwriting previous definition",
                            def.id(),
                            fileId
                        );
                    }

                    newDefs.put(def.id(), def);
                    LOGGER.debug(
                        "[DataDrivenItems] Loaded: {} -> '{}'",
                        def.id(),
                        def.displayName()
                    );
                } else {
                    skipped++;
                }
            } catch (Exception e) {
                LOGGER.error(
                    "[DataDrivenItems] Failed to read resource {}: {}",
                    fileId,
                    e.getMessage()
                );
                skipped++;
            }
        }

        // Merge into the registry (not replace) so the server listener doesn't
        // overwrite client-only definitions on integrated server
        DataDrivenItemRegistry.mergeAll(newDefs);

        LOGGER.info(
            "[DataDrivenItems] Loaded {} item definitions ({} skipped) from {} JSON files",
            newDefs.size(),
            skipped,
            resources.size()
        );
    }
}
