/*
 *  Super Lead rope mod
 *  Copyright (C)  2025  R3944Realms
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR 阿 PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package top.r3944realms.superleadrope.content.item;

import net.minecraft.core.BlockPos;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TieredItem;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraftforge.common.extensions.IForgeItem;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.superleadrope.api.SuperLeadRopeApi;
import top.r3944realms.superleadrope.api.type.capabilty.ILeashData;
import top.r3944realms.superleadrope.content.SLPToolTier;
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
import top.r3944realms.superleadrope.core.register.SLPSoundEvents;
import top.r3944realms.superleadrope.util.capability.LeashDataInnerAPI;

import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * The type Super lead rope item.
 */
//TODO:
// 1. 可抛掷使用 ***（下个版本实现）
// - 可转移拴绳
// 2. 多绑定（一个生物可以被多个加强拴绳绑定，产生共同作用效果）
// 3. 支持更多支撑方块
// 4. 可配置的生物栓效果（通过标签系统可配置哪些额外实体可被拴住）
// 5. 可自定义拴绳渲染位置（以匹配不同的生物模型）
// 6. 不可消耗的（但是有耐久，需要修复, 通过消耗原版拴绳恢复，每次多重绑定就会消耗1点耐久）
// 实现拴生物，在生物的interact方法里去写相关逻辑
// （尝试0 mixin 实现 加强拴绳逻辑）
public class SuperLeadRopeItem extends TieredItem implements IForgeItem {
    // 配置常量
    // 【手动调节,可以通过附魔获取更远抛掷和抛掷距离 - x1.3】//TODO:将可抛掷实现留到下次编写
    // 可以做个大于一定距离时远距离使用时抛出拴绳的实体，击中生物才栓中的
    private static final double SHORT_RANGE = 5.0D;
    private static final float THROW_SPEED = 1.5F;


    /**
     * Instantiates a new Super lead rope item.
     *
     * @param pProperties the p properties
     */
    public SuperLeadRopeItem(@NotNull Properties pProperties) {
        super(SLPToolTier.STRING,
                pProperties
                        .durability(1024)
                        .setNoRepair()
        );
    }

    //通过按键 可抛掷启用/关闭实现（不会影响use逻辑）
    @Override
    public @NotNull InteractionResultHolder<ItemStack> use(@NotNull Level pLevel, @NotNull Player pPlayer, @NotNull InteractionHand pUsedHand) {
        ItemStack lead = pPlayer.getItemInHand(pUsedHand);
        if(!pLevel.isClientSide) {
            if (canUse(lead)) return InteractionResultHolder.pass(lead);
            return super.use(pLevel, pPlayer, pUsedHand);

        }
        return InteractionResultHolder.success(lead);
    }

    /**
     * Can use boolean.
     *
     * @param itemStack the item stack
     * @return the boolean
     */
    public static boolean canUse(@NotNull ItemStack itemStack) {
        return itemStack.getDamageValue() < 1000;
    }

    @Override
    public @NotNull InteractionResult useOn(@NotNull UseOnContext context) {
        Level level = context.getLevel();
        BlockPos pos = context.getClickedPos();
        BlockState state = level.getBlockState(pos);
        ItemStack itemStack = context.getItemInHand();
        if (canUse(itemStack)) return InteractionResult.SUCCESS;
        if(SuperLeashKnotEntity.isSupportBlock(state)) {
            Player player = context.getPlayer();
            if(!level.isClientSide && player != null) {
                return bindToBlock(player, level, pos, itemStack, false) ? InteractionResult.CONSUME : InteractionResult.SUCCESS;
            }
        }
        return InteractionResult.SUCCESS;
    }

    /**
     * 右键蹲下绑定到另一实体上
     *
     * @param newHolder 新实体
     * @param player    明确持有玩家
     * @param level     维度世界
     * @return 是否成功 boolean
     */
    public static boolean bindToEntity(Entity newHolder, Player player, Level level) {
        return bindToEntity(newHolder, player, level, player.getOnPos());
    }

    /**
     * 右键蹲下绑定到另一实体上
     *
     * @param newHolder 新实体
     * @param player    明确持有玩家
     * @param level     维度世界
     * @param pos       坐标（一般是明确持有玩家的位置）
     * @return 是否成功 boolean
     */
    public static boolean bindToEntity(Entity newHolder, Player player, Level level, BlockPos pos) {
        boolean isSuccess = false;

        // 查找当前玩家持有的可拴生物
        List<Entity> list = SuperLeadRopeApi.leashableInArea(
                level, pos.getCenter(),
                entity -> SuperLeadRopeApi.isLeashHolder(entity, player.getUUID())
        );

        for (Entity e : list) {
            Optional<ILeashData> leashDataOpt = LeashDataInnerAPI.getLeashData(e);

            if (leashDataOpt.map(i -> i.canBeAttachedTo(newHolder)).orElse(false)) {
                leashDataOpt.ifPresent(i -> i.transferLeash(player.getUUID(), newHolder));
                isSuccess = true;
            }
        }

        if (!isSuccess) {
            return false;
        } else {
            level.gameEvent(GameEvent.ENTITY_INTERACT, pos, GameEvent.Context.of(player));
            level.playSound(null, newHolder.getOnPos(), SLPSoundEvents.LEAD_UNTIED.get(), SoundSource.PLAYERS);
            return true;
        }
    }

    /**
     * 右键蹲下绑定到支持方块上
     *
     * @param player         明确持有玩家
     * @param level          维度世界
     * @param leashStack     拴绳物品实例
     * @param shouldBindSelf 是否应该触发拴自己逻辑检查
     * @return 是否成功 boolean
     */
    public static boolean bindToBlock(Player player, Level level, ItemStack leashStack, boolean shouldBindSelf) {
        return bindToBlock(player, level, player.getOnPos(), leashStack, shouldBindSelf);
    }

    /**
     * 右键蹲下绑定到支持方块上
     *
     * @param player         明确持有玩家
     * @param level          维度世界
     * @param pos            坐标（一般是明确持有玩家的位置）
     * @param leashStack     拴绳物品实例
     * @param shouldBindSelf 是否应该触发拴自己逻辑检查
     * @return 是否成功 boolean
     */
    public static boolean bindToBlock(Player player, Level level, BlockPos pos, ItemStack leashStack, boolean shouldBindSelf) {
        SuperLeashKnotEntity knot = null;
        AtomicBoolean isSuccess = new AtomicBoolean(false);
        UUID uuid = player.getUUID();

        List<Entity> list = SuperLeadRopeApi.leashableInArea(level, pos.getCenter(),
                entity -> SuperLeadRopeApi.isLeashHolder(entity, uuid));

        // 情况一：拴自己到新 knot
        if (shouldBindSelf && list.isEmpty()) {
            if (leashStack.isEmpty() || !canUse(leashStack)) {
                return false;
            }
                knot = SuperLeashKnotEntity.getOrCreateKnot(level, pos);
                knot.playPlacementSound();

                SuperLeashKnotEntity finalKnot = knot;
                LeashDataInnerAPI.getLeashData(player).ifPresent(i -> {
                    if (i.canBeAttachedTo(finalKnot)) {
                        if (!level.isClientSide) i.addLeash(finalKnot);
                        isSuccess.set(true);
                    }
                });
        }
        // 情况二：把已有生物拴到 knot
        else if (!list.isEmpty()) {
            for (Entity e : list) {
                if (knot == null) {
                    knot = SuperLeashKnotEntity.getOrCreateKnot(level, pos);
                    knot.playPlacementSound();
                }
                SuperLeashKnotEntity finalKnot = knot;

                LeashDataInnerAPI.getLeashData(e).ifPresent(i -> {
                    if (i.canBeAttachedTo(finalKnot)) {
                        if (!level.isClientSide) i.transferLeash(uuid, finalKnot);
                        isSuccess.set(true);
                    }
                });
            }
        }

        if (isSuccess.get()) {
            level.gameEvent(GameEvent.BLOCK_ATTACH, pos, GameEvent.Context.of(player));
            return true;
        }
        return false;
    }
}
