package com.tiedup.remake.util;

import com.tiedup.remake.compat.mca.MCACompat;
import com.tiedup.remake.state.IRestrainable;
import com.tiedup.remake.state.PlayerBindState;
import com.tiedup.remake.v2.BodyRegionV2;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import org.jetbrains.annotations.Nullable;

/**
 *
 * Provides convenient methods for obtaining IRestrainable instances from various entity types.
 *
 * <h2>Purpose</h2>
 * This helper abstracts the complexity of determining whether an entity can be kidnapped/restrained
 * and provides a unified way to access the IRestrainable interface across different entity types.
 *
 * <h2>Supported Entity Types</h2>
 * <ul>
 *   <li><b>Player</b>: Uses {@link PlayerBindState} singleton</li>
 *   <li><b>EntityDamsel</b>: Implements IRestrainable directly</li>
 *   <li><b>EntityKidnapper</b>: Implements IRestrainable directly</li>
 *   <li><b>Other entities</b>: Returns null (not kidnappable)</li>
 * </ul>
 *
 * <h2>Usage Example</h2>
 * <pre>{@code
 * public InteractionResult interactLivingEntity(ItemStack stack, Player user,
 *                                                LivingEntity target, InteractionHand hand) {
 *     IRestrainable state = KidnappedHelper.getKidnappedState(target);
 *     if (state == null) {
 *         return InteractionResult.PASS; // Entity cannot be restrained
 *     }
 *
 *     if (state.isTiedUp()) {
 *         user.sendSystemMessage(Component.literal("Already tied up!"));
 *         return InteractionResult.FAIL;
 *     }
 *
 *     state.equip(BodyRegionV2.ARMS, stack.copy());
 *     return InteractionResult.SUCCESS;
 * }
 * }</pre>
 */
public class KidnappedHelper {

    /**
     * Get the IRestrainable instance for any living entity.
     *
     * <p>This method determines the appropriate IRestrainable implementation based on entity type:
     * <ul>
     *   <li><b>Player</b>: Returns {@link PlayerBindState#getInstance(Player)}</li>
     *   <li><b>IRestrainable implementer</b> (NPCs): Returns the entity itself (cast to IRestrainable)</li>
     *   <li><b>Other entities</b>: Returns null (entity cannot be kidnapped)</li>
     * </ul>
     *
     * @param entity The living entity to check
     * @return The IRestrainable instance, or null if entity cannot be kidnapped
     */
    @Nullable
    public static IRestrainable getKidnappedState(LivingEntity entity) {
        if (entity == null) {
            return null;
        }

        // For Players: Use PlayerBindState singleton
        if (entity instanceof Player player) {
            return PlayerBindState.getInstance(player);
        }

        // For NPCs that implement IRestrainable (EntityDamsel, EntityKidnapper, etc.)
        if (entity instanceof IRestrainable kidnapped) {
            return kidnapped;
        }

        // MCA Compatibility: Check if entity is an MCA villager
        if (MCACompat.isMCALoaded() && MCACompat.isMCAVillager(entity)) {
            IRestrainable mcaState = MCACompat.getKidnappedState(entity);
            com.tiedup.remake.core.TiedUpMod.LOGGER.debug(
                "[KidnappedHelper] MCA villager {} -> state: {}",
                entity.getName().getString(),
                mcaState != null ? mcaState.getClass().getSimpleName() : "null"
            );
            return mcaState;
        }

        // Entity cannot be kidnapped
        return null;
    }

    /**
     * Check if an entity can be kidnapped/restrained.
     *
     * @param entity The living entity to check
     * @return true if the entity implements IRestrainable or is a Player
     */
    public static boolean canBeKidnapped(LivingEntity entity) {
        return getKidnappedState(entity) != null;
    }

    /**
     * Check if an entity is currently tied up.
     *
     * <p>Convenience method that combines {@link #getKidnappedState(LivingEntity)}
     * and {@link IRestrainable#isTiedUp()}.
     *
     * @param entity The living entity to check
     * @return true if the entity is tied up, false otherwise
     */
    public static boolean isTiedUp(LivingEntity entity) {
        IRestrainable state = getKidnappedState(entity);
        return state != null && state.isTiedUp();
    }

    /**
     * Check if an entity is currently gagged.
     *
     * <p>Convenience method that combines {@link #getKidnappedState(LivingEntity)}
     * and {@link IRestrainable#isGagged()}.
     *
     * @param entity The living entity to check
     * @return true if the entity is gagged, false otherwise
     */
    public static boolean isGagged(LivingEntity entity) {
        IRestrainable state = getKidnappedState(entity);
        return state != null && state.isGagged();
    }

    /**
     * Check if an entity is currently blindfolded.
     *
     * <p>Convenience method that combines {@link #getKidnappedState(LivingEntity)}
     * and {@link IRestrainable#isBlindfolded()}.
     *
     * @param entity The living entity to check
     * @return true if the entity is blindfolded, false otherwise
     */
    public static boolean isBlindfolded(LivingEntity entity) {
        IRestrainable state = getKidnappedState(entity);
        return state != null && state.isBlindfolded();
    }

    /**
     * Check if an entity has a collar.
     *
     * <p>Convenience method that combines {@link #getKidnappedState(LivingEntity)}
     * and {@link IRestrainable#hasCollar()}.
     *
     * @param entity The living entity to check
     * @return true if the entity has a collar, false otherwise
     */
    public static boolean hasCollar(LivingEntity entity) {
        IRestrainable state = getKidnappedState(entity);
        return state != null && state.hasCollar();
    }

    /**
     * Check if an entity is enslaved.
     *
     * <p>Convenience method that combines {@link #getKidnappedState(LivingEntity)}
     * and {@link IRestrainable#isSlave()}.
     *
     * @param entity The living entity to check
     * @return true if the entity is enslaved, false otherwise
     */
    /**
     */
    public static boolean isCaptive(LivingEntity entity) {
        IRestrainable state = getKidnappedState(entity);
        return state != null && state.isCaptive();
    }
}
