package com.tiedup.remake.v2.bondage;

import com.tiedup.remake.v2.BodyRegionV2;
import java.util.Set;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.Nullable;

/**
 * Core interface for V2 bondage items.
 *
 * Implemented by Item classes that can be equipped into V2 body regions.
 * Provides region occupation, 3D model info, pose/animation data,
 * and lifecycle hooks.
 */
public interface IV2BondageItem {
    // ===== REGIONS =====

    /**
     * Which body regions this item occupies.
     * Example: Armbinder returns {ARMS, HANDS, TORSO}.
     */
    Set<BodyRegionV2> getOccupiedRegions();

    /**
     * Stack-aware variant. Data-driven items override this to read regions from NBT/registry.
     * Default delegates to the no-arg version (backward compatible for hardcoded items).
     */
    default Set<BodyRegionV2> getOccupiedRegions(ItemStack stack) {
        return getOccupiedRegions();
    }

    /**
     * Which regions this item blocks from having other items.
     * Usually same as occupied, but could differ.
     * Example: Hood occupies HEAD but blocks {HEAD, EYES, EARS, MOUTH}.
     * Defaults to same as {@link #getOccupiedRegions()}.
     */
    default Set<BodyRegionV2> getBlockedRegions() {
        return getOccupiedRegions();
    }

    /**
     * Stack-aware variant. Data-driven items override this to read blocked regions from NBT/registry.
     */
    default Set<BodyRegionV2> getBlockedRegions(ItemStack stack) {
        return getBlockedRegions();
    }

    // ===== 3D MODELS =====

    /**
     * Get the glTF model location (.glb file).
     * Returns null for items without a 3D model (e.g., clothes-only items).
     */
    @Nullable
    ResourceLocation getModelLocation();

    /**
     * Stack-aware variant. Data-driven items override this to read model from NBT/registry.
     */
    @Nullable
    default ResourceLocation getModelLocation(ItemStack stack) {
        return getModelLocation();
    }

    // ===== POSES & ANIMATIONS =====

    /**
     * Priority for pose conflicts. Higher value wins.
     * Example: Fullbind (100) > Armbinder (50) > Handcuffs (30) > Collar (10) > None (0).
     */
    int getPosePriority();

    /**
     * Stack-aware variant for pose priority.
     */
    default int getPosePriority(ItemStack stack) {
        return getPosePriority();
    }

    // ===== ITEM STATE =====

    /**
     * Difficulty to escape (for struggle minigame). Higher = harder.
     */
    int getEscapeDifficulty();

    /**
     * Stack-aware variant for escape difficulty.
     */
    default int getEscapeDifficulty(ItemStack stack) {
        return getEscapeDifficulty();
    }

    // ===== RENDERING =====

    /**
     * Whether this item supports color variants (texture_red.png, etc.).
     */
    boolean supportsColor();

    /**
     * Stack-aware variant for color support.
     */
    default boolean supportsColor(ItemStack stack) {
        return supportsColor();
    }

    /**
     * Whether this item supports a slim model variant (Alex-style 3px arms).
     */
    boolean supportsSlimModel();

    /**
     * Stack-aware variant for slim model support.
     */
    default boolean supportsSlimModel(ItemStack stack) {
        return supportsSlimModel();
    }

    /**
     * Get the slim model location (.glb) for Alex-style players.
     * Only meaningful if {@link #supportsSlimModel()} returns true.
     */
    @Nullable
    default ResourceLocation getSlimModelLocation() {
        return null;
    }

    /**
     * Stack-aware variant for slim model location.
     */
    @Nullable
    default ResourceLocation getSlimModelLocation(ItemStack stack) {
        return getSlimModelLocation();
    }

    // ===== LIFECYCLE HOOKS =====

    /**
     * Called when this item is equipped onto an entity.
     */
    default void onEquipped(ItemStack stack, LivingEntity entity) {}

    /**
     * Called when this item is unequipped from an entity.
     */
    default void onUnequipped(ItemStack stack, LivingEntity entity) {}

    /**
     * Whether this item can be equipped on the given entity right now.
     */
    default boolean canEquip(ItemStack stack, LivingEntity entity) {
        return true;
    }

    /**
     * Whether this item can be unequipped from the given entity right now.
     */
    default boolean canUnequip(ItemStack stack, LivingEntity entity) {
        return true;
    }
}
