package com.tiedup.remake.v2.bondage;

import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.state.IBondageState;
import com.tiedup.remake.state.PlayerBindState;
import com.tiedup.remake.tasks.TyingTask;
import com.tiedup.remake.tasks.V2TyingPlayerTask;
import com.tiedup.remake.util.KidnappedHelper;
import com.tiedup.remake.v2.BodyRegionV2;
import com.tiedup.remake.v2.bondage.capability.V2EquipmentHelper;
import com.tiedup.remake.v2.bondage.V2EquipResult;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;

/**
 * Handles the tying interaction flow for V2 data-driven ARMS items.
 *
 * <p>Originally extracted from the former {@code ItemBind.interactLivingEntity()},
 * now the canonical tying flow for all data-driven ARMS items.</p>
 */
public final class TyingInteractionHelper {

    private TyingInteractionHelper() {}

    /**
     * Handle right-click tying of a target entity with a V2 ARMS item.
     * Creates/continues a V2TyingPlayerTask.
     */
    public static InteractionResult handleTying(
        ServerPlayer player,
        LivingEntity target,
        ItemStack stack,
        InteractionHand hand
    ) {
        IBondageState targetState = KidnappedHelper.getKidnappedState(target);
        if (targetState == null) return InteractionResult.PASS;

        // Kidnapper can't be tied themselves
        IBondageState kidnapperState = KidnappedHelper.getKidnappedState(player);
        if (kidnapperState != null && kidnapperState.isTiedUp()) {
            return InteractionResult.PASS;
        }

        // Already tied — try to swap (check both V1 state and V2 region to prevent dual-bind)
        if (targetState.isTiedUp() || V2EquipmentHelper.isRegionOccupied(target, BodyRegionV2.ARMS)) {
            if (stack.isEmpty()) return InteractionResult.PASS;
            ItemStack oldBind = V2EquipmentHelper.unequipFromRegion(target, BodyRegionV2.ARMS);
            if (!oldBind.isEmpty()) {
                V2EquipResult result = V2EquipmentHelper.equipItem(target, stack.copy());
                if (result.isSuccess()) {
                    stack.shrink(1);
                    target.spawnAtLocation(oldBind);
                    TiedUpMod.LOGGER.debug("[TyingInteraction] Swapped bind on {}", target.getName().getString());
                    return InteractionResult.SUCCESS;
                } else {
                    // Equip failed — rollback: re-equip old bind
                    V2EquipResult rollback = V2EquipmentHelper.equipItem(target, oldBind);
                    if (!rollback.isSuccess()) {
                        // Rollback also failed — drop old bind as safety net
                        target.spawnAtLocation(oldBind);
                        TiedUpMod.LOGGER.warn("[TyingInteraction] Swap AND rollback failed, dropped old bind for {}", target.getName().getString());
                    } else {
                        TiedUpMod.LOGGER.debug("[TyingInteraction] Swap failed, rolled back old bind on {}", target.getName().getString());
                    }
                    return InteractionResult.PASS;
                }
            }
            return InteractionResult.PASS;
        }

        // Distance + line-of-sight (skip for self-tying)
        boolean isSelfTying = player.equals(target);
        if (!isSelfTying) {
            if (player.distanceTo(target) > 4.0 || !player.hasLineOfSight(target)) {
                return InteractionResult.PASS;
            }
        }

        // Create/continue tying task
        PlayerBindState playerState = PlayerBindState.getInstance(player);
        if (playerState == null) return InteractionResult.PASS;

        int tyingSeconds = SettingsAccessor.getTyingPlayerTime(player.level().getGameRules());

        V2TyingPlayerTask newTask = new V2TyingPlayerTask(
            stack.copy(),
            stack,
            targetState,
            target,
            tyingSeconds,
            player.level(),
            player
        );

        TyingTask currentTask = playerState.tasks().getCurrentTyingTask();
        if (currentTask == null
            || !(currentTask instanceof V2TyingPlayerTask)
            || !currentTask.isSameTarget(target)
            || currentTask.isOutdated()
            || !ItemStack.matches(currentTask.getBind(), stack)) {
            // Start new task (also handles case where existing task is V1 TyingPlayerTask)
            playerState.tasks().setCurrentTyingTask(newTask);
            newTask.start();
        } else {
            newTask = (V2TyingPlayerTask) currentTask;
        }

        newTask.update();

        if (newTask.isStopped()) {
            // Item already consumed by V2TyingPlayerTask.onComplete() — don't shrink again
            playerState.tasks().setCurrentTyingTask(null);
            TiedUpMod.LOGGER.info("[TyingInteraction] {} tied {}", player.getName().getString(), target.getName().getString());
        }

        return InteractionResult.SUCCESS;
    }
}
