package com.tiedup.remake.dispenser;

import com.tiedup.remake.state.IBondageState;
import com.tiedup.remake.util.KidnappedHelper;
import java.util.List;
import net.minecraft.core.BlockPos;
import net.minecraft.core.BlockSource;
import net.minecraft.core.Direction;
import net.minecraft.core.dispenser.DefaultDispenseItemBehavior;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.DispenserBlock;
import net.minecraft.world.phys.AABB;

/**
 * Base class for dispenser behaviors that equip bondage items on entities.
 *
 * When a dispenser containing a bondage item fires, it will attempt to
 * equip the item on any valid entity (Player or NPC) standing in front of it.
 *
 * Based on original BehaviorDispenserEquipBondage from 1.12.2
 */
public abstract class EquipBondageDispenseBehavior
    extends DefaultDispenseItemBehavior
{

    @Override
    protected ItemStack execute(BlockSource source, ItemStack stack) {
        Direction facing = source
            .getBlockState()
            .getValue(DispenserBlock.FACING);
        BlockPos dispenserPos = new BlockPos(
            (int) source.x(),
            (int) source.y(),
            (int) source.z()
        );
        BlockPos targetPos = dispenserPos.relative(facing);

        // Create expanded AABB to catch entities (players are 1.8 blocks tall)
        AABB searchArea = new AABB(targetPos).inflate(0.5, 1.0, 0.5);

        // Find all living entities in front of the dispenser
        List<LivingEntity> entities = source
            .getLevel()
            .getEntitiesOfClass(LivingEntity.class, searchArea);

        // Try to equip on the first valid entity
        for (LivingEntity entity : entities) {
            IBondageState state = KidnappedHelper.getKidnappedState(entity);
            if (state != null && isValidItem(stack) && canEquip(state)) {
                ItemStack toEquip = stack.split(1);
                equip(state, toEquip);
                return stack;
            }
        }

        // No valid target - use default dispenser behavior (drop item)
        return super.execute(source, stack);
    }

    /**
     * Check if the item stack is valid for this behavior.
     *
     * @param stack The item stack to check
     * @return true if the item can be equipped by this behavior
     */
    protected abstract boolean isValidItem(ItemStack stack);

    /**
     * Check if the entity state allows equipping this item type.
     *
     * @param state The target entity's kidnapped state
     * @return true if the item can be equipped on this entity
     */
    protected abstract boolean canEquip(IBondageState state);

    /**
     * Equip the item on the entity.
     *
     * @param state The target entity's kidnapped state
     * @param stack The item stack to equip
     */
    protected abstract void equip(IBondageState state, ItemStack stack);
}
