package com.tiedup.remake.util;

import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.items.base.IHasResistance;
import com.tiedup.remake.state.IBondageState;
import com.tiedup.remake.v2.bondage.CollarHelper;
import com.tiedup.remake.v2.BodyRegionV2;
import java.util.UUID;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.Nullable;

/**
 * Utility class for applying restraints to entities.
 *
 *
 * This class provides methods for applying various restraints (binds, gags,
 * blindfolds, etc.) to targets with consistent validation. Used by:
 * - KidnapperCaptureGoal
 * - KidnapperPunishGoal
 * - EntityRopeArrow
 * - Other capture/restraint mechanics
 */
public final class RestraintApplicator {

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

    // ==================== BIND ====================

    /**
     * Apply a bind or tighten existing binds.
     *
     * @param target The target entity
     * @param bind The bind item to apply if needed
     * @return true if bind was applied or tightened
     */
    public static boolean applyOrTightenBind(
        LivingEntity target,
        ItemStack bind
    ) {
        IBondageState state = KidnappedHelper.getKidnappedState(target);
        if (state == null) {
            return false;
        }

        ItemStack currentBind = state.getEquipment(BodyRegionV2.ARMS);
        if (currentBind.isEmpty()) {
            // No bind - apply new one
            if (bind != null && !bind.isEmpty()) {
                state.equip(BodyRegionV2.ARMS, bind.copy());
                return true;
            }
            return false;
        }

        // Tighten existing bind - reset resistance to max
        if (currentBind.getItem() instanceof IHasResistance bindItem) {
            int maxResistance = bindItem.getBaseResistance(target);
            state.setCurrentBindResistance(maxResistance);
            return true;
        }

        return false;
    }

    /**
     * Tighten an entity's binds, resetting resistance to max.
     * This happens when a guard catches someone struggling.
     *
     * <p>Consolidated from EntityKidnapper, EntityMaid, EntitySlaveTrader, KidnapperPunishGoal.</p>
     *
     * @param state The prisoner's kidnapped state
     * @param prisoner The prisoner entity
     * @return true if binds were tightened, false if no binds equipped
     */
    public static boolean tightenBind(
        IBondageState state,
        LivingEntity prisoner
    ) {
        if (state == null) return false;

        ItemStack bind = state.getEquipment(BodyRegionV2.ARMS);
        if (bind.isEmpty()) {
            return false;
        }

        if (bind.getItem() instanceof IHasResistance resistItem) {
            int baseResistance = resistItem.getBaseResistance(prisoner);
            resistItem.setCurrentResistance(bind, baseResistance);

            // Notify the prisoner
            if (prisoner instanceof ServerPlayer serverPlayer) {
                serverPlayer.sendSystemMessage(
                    Component.translatable(
                        "msg.tiedup.restraint.tightened"
                    ).withStyle(ChatFormatting.RED)
                );
            }

            TiedUpMod.LOGGER.debug(
                "[RestraintApplicator] Tightened {}'s binds (resistance reset to {})",
                prisoner.getName().getString(),
                baseResistance
            );
            return true;
        }

        return false;
    }

    // ==================== GAG ====================

    /**
     * Apply a gag to the target.
     *
     * @param target The target entity
     * @param gag The gag item to apply
     * @return true if successfully applied, false if already gagged or invalid
     */
    public static boolean applyGag(LivingEntity target, ItemStack gag) {
        IBondageState state = KidnappedHelper.getKidnappedState(target);
        if (state == null || gag == null || gag.isEmpty()) {
            return false;
        }
        if (state.isGagged()) {
            return false; // Already gagged
        }

        state.equip(BodyRegionV2.MOUTH, gag.copy());
        return true;
    }

    /**
     * Apply a gag only if the target doesn't have one.
     *
     * @param target The target entity
     * @param gag The gag item to apply
     * @return true if gag was applied
     */
    public static boolean applyGagIfMissing(
        LivingEntity target,
        ItemStack gag
    ) {
        IBondageState state = KidnappedHelper.getKidnappedState(target);
        if (state == null || gag == null || gag.isEmpty()) {
            return false;
        }

        ItemStack currentGag = state.getEquipment(BodyRegionV2.MOUTH);
        if (!currentGag.isEmpty()) {
            return false; // Already has gag
        }

        state.equip(BodyRegionV2.MOUTH, gag.copy());
        return true;
    }

    // ==================== BLINDFOLD ====================

    /**
     * Apply a blindfold to the target.
     *
     * @param target The target entity
     * @param blindfold The blindfold item to apply
     * @return true if successfully applied, false if already blindfolded or invalid
     */
    public static boolean applyBlindfold(
        LivingEntity target,
        ItemStack blindfold
    ) {
        IBondageState state = KidnappedHelper.getKidnappedState(target);
        if (state == null || blindfold == null || blindfold.isEmpty()) {
            return false;
        }
        if (state.isBlindfolded()) {
            return false; // Already blindfolded
        }

        state.equip(BodyRegionV2.EYES, blindfold.copy());
        return true;
    }

    /**
     * Apply a blindfold only if the target doesn't have one.
     *
     * @param target The target entity
     * @param blindfold The blindfold item to apply
     * @return true if blindfold was applied
     */
    public static boolean applyBlindfoldIfMissing(
        LivingEntity target,
        ItemStack blindfold
    ) {
        IBondageState state = KidnappedHelper.getKidnappedState(target);
        if (state == null || blindfold == null || blindfold.isEmpty()) {
            return false;
        }

        ItemStack currentBlindfold = state.getEquipment(BodyRegionV2.EYES);
        if (!currentBlindfold.isEmpty()) {
            return false; // Already has blindfold
        }

        state.equip(BodyRegionV2.EYES, blindfold.copy());
        return true;
    }

    // ==================== MITTENS ====================

    /**
     * Apply mittens to the target.
     *
     * @param target The target entity
     * @param mittens The mittens item to apply
     * @return true if successfully applied, false if already has mittens or invalid
     */
    public static boolean applyMittens(LivingEntity target, ItemStack mittens) {
        IBondageState state = KidnappedHelper.getKidnappedState(target);
        if (state == null || mittens == null || mittens.isEmpty()) {
            return false;
        }
        if (state.hasMittens()) {
            return false; // Already has mittens
        }

        state.equip(BodyRegionV2.HANDS, mittens.copy());
        return true;
    }

    // ==================== EARPLUGS ====================

    /**
     * Apply earplugs to the target.
     *
     * @param target The target entity
     * @param earplugs The earplugs item to apply
     * @return true if successfully applied, false if already has earplugs or invalid
     */
    public static boolean applyEarplugs(
        LivingEntity target,
        ItemStack earplugs
    ) {
        IBondageState state = KidnappedHelper.getKidnappedState(target);
        if (state == null || earplugs == null || earplugs.isEmpty()) {
            return false;
        }
        if (state.hasEarplugs()) {
            return false; // Already has earplugs
        }

        state.equip(BodyRegionV2.EARS, earplugs.copy());
        return true;
    }

    // ==================== COLLAR ====================

    /**
     * Apply a collar to the target with owner information.
     *
     * @param target The target entity
     * @param collar The collar item to apply
     * @param ownerUUID The owner's UUID (can be null)
     * @param ownerName The owner's name (can be null)
     * @return true if successfully applied, false if already has collar or invalid
     */
    public static boolean applyCollar(
        LivingEntity target,
        ItemStack collar,
        @Nullable UUID ownerUUID,
        @Nullable String ownerName
    ) {
        IBondageState state = KidnappedHelper.getKidnappedState(target);
        if (state == null || collar == null || collar.isEmpty()) {
            return false;
        }
        if (state.hasCollar()) {
            return false; // Already has collar
        }

        ItemStack collarCopy = collar.copy();

        // Add owner if provided
        if (ownerUUID != null && CollarHelper.isCollar(collarCopy)) {
            CollarHelper.addOwner(
                collarCopy,
                ownerUUID,
                ownerName != null ? ownerName : "Unknown"
            );
        }

        state.equip(BodyRegionV2.NECK, collarCopy);
        return true;
    }

    /**
     * Apply a collar without owner information.
     *
     * @param target The target entity
     * @param collar The collar item to apply
     * @return true if successfully applied
     */
    public static boolean applyCollar(LivingEntity target, ItemStack collar) {
        return applyCollar(target, collar, null, null);
    }

    // ==================== BULK OPERATIONS ====================

    /**
     * Check if target has any restraints.
     *
     * @param target The target entity
     * @return true if target has any restraints
     */
    public static boolean hasAnyRestraint(LivingEntity target) {
        IBondageState state = KidnappedHelper.getKidnappedState(target);
        if (state == null) {
            return false;
        }
        return (
            state.isTiedUp() ||
            state.isGagged() ||
            state.isBlindfolded() ||
            state.hasMittens() ||
            state.hasEarplugs() ||
            state.hasCollar()
        );
    }

    /**
     * Get the kidnapped state for an entity.
     *
     * @param target The target entity
     * @return The IBondageState state, or null if not available
     */
    @Nullable
    public static IBondageState getState(LivingEntity target) {
        return KidnappedHelper.getKidnappedState(target);
    }
}
