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

import com.tiedup.remake.v2.bondage.datadriven.DataDrivenItemDefinition;
import com.tiedup.remake.v2.bondage.datadriven.DataDrivenItemRegistry;
import java.util.LinkedHashMap;
import java.util.Map;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;

/**
 * Resolves per-item tint colors by merging definition defaults with NBT overrides.
 *
 * <p>Priority (highest wins):
 * <ol>
 *   <li>NBT tag {@code tint_colors} on the ItemStack (player dye overrides)</li>
 *   <li>Default tint channels from the {@link DataDrivenItemDefinition}</li>
 * </ol>
 *
 * <p>Returns a map of tint channel name (e.g. "tintable_0") to RGB int (0xRRGGBB).
 * An empty map means no tint — the renderer should use white (no color modification).</p>
 */
@OnlyIn(Dist.CLIENT)
public final class TintColorResolver {

    private TintColorResolver() {}

    /**
     * Resolve tint colors for an ItemStack.
     *
     * <p>Hot-path: called once per rendered V2 item per frame. Skips the
     * {@link LinkedHashMap} allocation when neither the definition nor the
     * stack declares any tint channels — the common case for non-tintable
     * items (audit P2-04, 06-v2-bondage-rendering.md HIGH-5).</p>
     *
     * @param stack the equipped bondage item
     * @return channel-to-color map; empty (immutable {@link Map#of()}) if no
     *         tint channels defined or found
     */
    public static Map<String, Integer> resolve(ItemStack stack) {
        // Hot-path shortcut: both sources empty → return the singleton empty
        // map without allocating.
        DataDrivenItemDefinition def = DataDrivenItemRegistry.get(stack);
        boolean hasDefChannels =
            def != null &&
            def.tintChannels() != null &&
            !def.tintChannels().isEmpty();

        CompoundTag tag = stack.getTag();
        boolean hasNbtTints =
            tag != null && tag.contains("tint_colors", Tag.TAG_COMPOUND);

        if (!hasDefChannels && !hasNbtTints) {
            return Map.of();
        }

        Map<String, Integer> result = new LinkedHashMap<>();
        if (hasDefChannels) {
            result.putAll(def.tintChannels());
        }
        if (hasNbtTints) {
            CompoundTag tints = tag.getCompound("tint_colors");
            for (String key : tints.getAllKeys()) {
                // Type-check the NBT entry: a corrupt save or malicious client
                // might store a non-int value; getInt would silently return 0
                // and render pure black. Skip non-int entries.
                if (tints.contains(key, Tag.TAG_INT)) {
                    // Clamp to 24-bit RGB (no alpha in tint channels).
                    result.put(key, tints.getInt(key) & 0xFFFFFF);
                }
            }
        }
        return result;
    }
}
