package com.tiedup.remake.client.animation.util;

import com.tiedup.remake.items.base.PoseType;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;

/**
 * Builds legacy JSON-animation ResourceLocation IDs from pose / bind-mode
 * / variant components.
 *
 * <p><b>Legacy path.</b> The V2 player pipeline resolves animations from
 * GLB models via {@code GltfAnimationApplier.applyV2Animation} +
 * {@code RegionBoneMapper} and does not touch this class. Only two
 * callers remain:</p>
 * <ul>
 *   <li>{@code NpcAnimationTickHandler} — JSON fallback when a tied
 *       NPC has no GLB-bearing item equipped.</li>
 *   <li>{@code MixinVillagerEntityBaseModelMCA} — MCA villagers use
 *       their own capability system and don't flow through the V2
 *       item registry, so they stay on the JSON animation path.</li>
 * </ul>
 *
 * <p>New code should not depend on this class. Animation naming:
 * {@code {poseType}_{bindMode}_{variant}} (e.g.
 * {@code tiedup:straitjacket_arms_struggle}).</p>
 */
@OnlyIn(Dist.CLIENT)
public final class AnimationIdBuilder {

    private static final String NAMESPACE = "tiedup";

    // Bind mode suffixes
    private static final String SUFFIX_ARMS = "_arms";
    private static final String SUFFIX_LEGS = "_legs";

    // Variant suffixes
    private static final String SUFFIX_IDLE = "_idle";
    private static final String SUFFIX_WALK = "_walk";
    private static final String SUFFIX_STRUGGLE = "_struggle";
    private static final String SUFFIX_SNEAK = "_sneak";

    private AnimationIdBuilder() {
        // Utility class - no instantiation
    }

    /**
     * Get base animation name from pose type.
     * Delegates to {@link PoseType#getAnimationId()}.
     *
     * @param poseType Pose type
     * @return Base name string
     */
    public static String getBaseName(PoseType poseType) {
        return poseType.getAnimationId();
    }

    /**
     * Get suffix for bind mode derived from region flags.
     *
     * @param armsBound whether ARMS region is occupied
     * @param legsBound whether LEGS region is occupied
     * @return Suffix string: "" for FULL (both), "_arms" for arms-only, "_legs" for legs-only
     */
    public static String getModeSuffix(boolean armsBound, boolean legsBound) {
        if (armsBound && legsBound) return ""; // FULL has no suffix
        if (armsBound) return SUFFIX_ARMS;
        if (legsBound) return SUFFIX_LEGS;
        return ""; // neither bound = no suffix (shouldn't happen in practice)
    }

    /**
     * Get bind type name for SIT/KNEEL animations.
     * Delegates to {@link PoseType#getBindTypeName()}.
     *
     * @param poseType Pose type
     * @return Bind type name ("basic", "straitjacket", "wrap", "latex_sack")
     */
    public static String getBindTypeName(PoseType poseType) {
        return poseType.getBindTypeName();
    }

    // Unified Build Method

    /**
     * Build animation ID string for entities.
     *
     * <p>This method handles all cases:
     * <ul>
     *   <li>Standing poses: tied_up_basic_idle, straitjacket_struggle, etc.</li>
     *   <li>Sitting poses: sit_basic_idle, sit_free_idle, etc.</li>
     *   <li>Kneeling poses: kneel_basic_idle, kneel_wrap_struggle, etc.</li>
     * </ul>
     *
     * @param poseType The bind pose type (STANDARD, STRAITJACKET, etc.)
     * @param armsBound whether ARMS region is occupied
     * @param legsBound whether LEGS region is occupied
     * @param positionPrefix Position prefix ("sit", "kneel") or null for standing
     * @param isStruggling Whether entity is struggling
     * @param hasBind Whether entity has a bind equipped
     * @return Animation ID string (without namespace)
     */
    public static String build(
        PoseType poseType,
        boolean armsBound,
        boolean legsBound,
        String positionPrefix,
        boolean isStruggling,
        boolean hasBind
    ) {
        return build(
            poseType,
            armsBound,
            legsBound,
            positionPrefix,
            isStruggling,
            hasBind,
            false
        );
    }

    /**
     * Build animation ID string for entities with sneak support.
     *
     * @param poseType The bind pose type (STANDARD, STRAITJACKET, etc.)
     * @param armsBound whether ARMS region is occupied
     * @param legsBound whether LEGS region is occupied
     * @param positionPrefix Position prefix ("sit", "kneel") or null for standing
     * @param isStruggling Whether entity is struggling
     * @param hasBind Whether entity has a bind equipped
     * @param isSneaking Whether entity is sneaking
     * @return Animation ID string (without namespace)
     */
    public static String build(
        PoseType poseType,
        boolean armsBound,
        boolean legsBound,
        String positionPrefix,
        boolean isStruggling,
        boolean hasBind,
        boolean isSneaking
    ) {
        return build(
            poseType,
            armsBound,
            legsBound,
            positionPrefix,
            isStruggling,
            hasBind,
            isSneaking,
            false
        );
    }

    /**
     * Build animation ID string for entities with sneak and movement support.
     *
     * @param poseType The bind pose type (STANDARD, STRAITJACKET, etc.)
     * @param armsBound whether ARMS region is occupied
     * @param legsBound whether LEGS region is occupied
     * @param positionPrefix Position prefix ("sit", "kneel") or null for standing
     * @param isStruggling Whether entity is struggling
     * @param hasBind Whether entity has a bind equipped
     * @param isSneaking Whether entity is sneaking
     * @param isMoving Whether entity is moving
     * @return Animation ID string (without namespace)
     */
    public static String build(
        PoseType poseType,
        boolean armsBound,
        boolean legsBound,
        String positionPrefix,
        boolean isStruggling,
        boolean hasBind,
        boolean isSneaking,
        boolean isMoving
    ) {
        String sneakSuffix = isSneaking ? SUFFIX_SNEAK : "";

        // Determine variant suffix based on state priority: struggle > walk > idle
        String variantSuffix;
        if (isStruggling) {
            variantSuffix = SUFFIX_STRUGGLE;
        } else if (isMoving && poseType == PoseType.DOG) {
            // DOG pose has a walking animation (tied_up_dog_walk.json)
            variantSuffix = SUFFIX_WALK;
        } else {
            variantSuffix = SUFFIX_IDLE;
        }

        // SIT or KNEEL pose
        if (positionPrefix != null) {
            if (!hasBind) {
                // No bind: free pose (arms natural)
                return positionPrefix + "_free" + sneakSuffix + variantSuffix;
            }

            // Has bind
            String bindTypeName;
            if (legsBound && !armsBound) {
                // LEGS-only mode = arms free
                bindTypeName = "legs";
            } else {
                // FULL or ARMS mode
                bindTypeName = getBindTypeName(poseType);
            }
            return (
                positionPrefix +
                "_" +
                bindTypeName +
                sneakSuffix +
                variantSuffix
            );
        }

        // Standing pose (no position prefix)
        String baseName = getBaseName(poseType);
        String modeSuffix = getModeSuffix(armsBound, legsBound);

        // LEGS-only mode: only lock legs, arms are free - no idle/struggle variants needed
        if (legsBound && !armsBound) {
            return baseName + modeSuffix;
        }

        return baseName + modeSuffix + sneakSuffix + variantSuffix;
    }

    /**
     * Build animation ResourceLocation for SIT or KNEEL pose.
     *
     * @param posePrefix "sit" or "kneel"
     * @param poseType Bind pose type
     * @param armsBound whether ARMS region is occupied
     * @param legsBound whether LEGS region is occupied
     * @param isStruggling Whether entity is struggling
     * @return Animation ResourceLocation
     */
    public static ResourceLocation buildPositionAnimation(
        String posePrefix,
        PoseType poseType,
        boolean armsBound,
        boolean legsBound,
        boolean isStruggling
    ) {
        String bindTypeName;
        if (legsBound && !armsBound) {
            bindTypeName = "legs";
        } else {
            bindTypeName = getBindTypeName(poseType);
        }

        String variantSuffix = isStruggling ? SUFFIX_STRUGGLE : SUFFIX_IDLE;
        String animationName = posePrefix + "_" + bindTypeName + variantSuffix;
        return ResourceLocation.fromNamespaceAndPath(NAMESPACE, animationName);
    }

    /**
     * Build animation ResourceLocation for SIT or KNEEL pose when NOT bound.
     *
     * @param posePrefix "sit" or "kneel"
     * @return Animation ResourceLocation for free pose
     */
    public static ResourceLocation buildFreePositionAnimation(
        String posePrefix
    ) {
        String animationName = posePrefix + "_free" + SUFFIX_IDLE;
        return ResourceLocation.fromNamespaceAndPath(NAMESPACE, animationName);
    }
}
