package com.r3944realms.leashedplayer.content.commands;

import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.FloatArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.config.LeashPlayerCommonConfig;
import com.r3944realms.leashedplayer.content.gamerules.GameruleRegistry;
import com.r3944realms.leashedplayer.content.gamerules.Server.CreateLeashFenceKnotEntityIfAbsent;
import com.r3944realms.leashedplayer.modInterface.IEntityLeadExtension;
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.commands.arguments.EntityArgument;
import net.minecraft.commands.arguments.coordinates.BlockPosArgument;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Leashable;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import static com.r3944realms.leashedplayer.content.commands.Command.getLiterArgumentBuilderOfCSS;

public class LeashCommand {
    public static final Integer MIN_VALUE = LeashPlayerCommonConfig.MinimumLeashLengthCanBeSet.get();
    public static final Integer MAX_VALUE = LeashPlayerCommonConfig.MaximumLeashLengthCanBeSet.get();
    private final static String LEASHEDPLAYER_LEASH_MESSAGE_ = "leashedplayer.command.leash.message.";

    public final static String LEASH_FAILED = LEASHEDPLAYER_LEASH_MESSAGE_ + "leash.length.failed";

    public final static String  LEASH_LENGTH_SHOW = LEASHEDPLAYER_LEASH_MESSAGE_ + "leash.length.show",
                                LEASH_LENGTH_SET = LEASHEDPLAYER_LEASH_MESSAGE_ + "leash.length.set",
                                LEASH_DATA = LEASHEDPLAYER_LEASH_MESSAGE_ + "leash.data",
                                LEASH_DATA_CLEAR = LEASH_DATA + ".clear"
                                ;

    public final static String  NO_LEASH_DATA = LEASH_DATA + ".null",
                                LEASH_DATA_SHOW = LEASH_DATA + ".show",
                                LEASH_DATA_SET = LEASH_DATA + ".set",
                                LEASH_DATA_SET_FAILED_DIFF_LEVEL = LEASH_DATA_SET + ".failed.diff_level",
                                LEASH_DATA_SET_FAILED_TOO_FAR = LEASH_DATA_SET + ".failed.too_far",
                                LEASH_DATA_SET_FAILED_NO_KNOT_EXISTED_IN_THAT_POS = LEASH_DATA_SET + ".failed.no_knot_exist_in_that_pos",
                                LEASH_DATA_SET_FAILED_FORBID_SAME_ENTITY = LEASH_DATA_SET + ".failed.forbid_same_entity",
                                LEASH_DATA_CLEAR_FAILED_NO_DATA = LEASH_DATA_CLEAR + ".leash.clear.failed.no_data"
                                ;

    public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
        boolean shouldUsePrefix = LeashPlayerCommonConfig.EnableLeashPlayerCommandPrefix.get();
        @Nullable List<LiteralArgumentBuilder<CommandSourceStack>> nodeList = shouldUsePrefix ? null : new ArrayList<>();
        LiteralArgumentBuilder<CommandSourceStack> literalArgumentBuilder = Commands.literal(com.r3944realms.leashedplayer.content.commands.Command.PREFIX);
        LiteralArgumentBuilder<CommandSourceStack> $$leashRoot = getLiterArgumentBuilderOfCSS("leash", !shouldUsePrefix, nodeList);

        Command<CommandSourceStack> getSelfLeashLength = context -> {
            CommandSourceStack source = context.getSource();
            try {
                ServerPlayer player = source.getPlayerOrException();
                float leashLength = ((IEntityLeadExtension)player).getLeashLength();
                source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SHOW, player.getDisplayName(), leashLength), true);
            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };
        Command<CommandSourceStack> getRefPlayerLeashLength = context -> {
            CommandSourceStack source = context.getSource();
            try {
                ServerPlayer player = EntityArgument.getPlayer(context, "targetPlayer");
                float leashLength = ((IEntityLeadExtension)player).getLeashLength();
                source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SHOW, player.getDisplayName(), leashLength), true);
            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };
        Command<CommandSourceStack> getRefPlayersLeashLength = context -> {
            CommandSourceStack source = context.getSource();
            try {
                Collection<ServerPlayer> playerCol = EntityArgument.getPlayers(context, "targetPlayers");
                playerCol.forEach(player -> {
                    float leashLength = ((IEntityLeadExtension) player).getLeashLength();
                    source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SHOW, player.getDisplayName(), leashLength), true);
                });
            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };
        Command<CommandSourceStack> getRefEntitiesLeashLength = context -> {
            CommandSourceStack source = context.getSource();
            try {
                Collection<? extends Entity> entities = EntityArgument.getEntities(context, "targetEntities");
                entities.stream().filter(i->i instanceof Leashable).forEach(entity -> {
                    float leashLength = ((IEntityLeadExtension) entity).getLeashLength();
                    source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SHOW, entity.getDisplayName(), leashLength), true);
                });
            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };
        Command<CommandSourceStack> setSelfLengthLeashLength = context -> {
            CommandSourceStack source = context.getSource();
            try {
                ServerPlayer player = source.getPlayerOrException();
                float leashLength = context.getArgument("leashLength", Float.class);
                IEntityLeadExtension player1 = (IEntityLeadExtension) player;
                player1.setLeashLength(leashLength);
                player1.setLeadLengthSync(false);
                source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SET, player.getDisplayName(), leashLength), true);
            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };
        Command<CommandSourceStack> setRefPlayerLengthLeashLength = context -> {
            CommandSourceStack source = context.getSource();
            try {
                ServerPlayer player = EntityArgument.getPlayer(context, "targetPlayer");
                float leashLength = context.getArgument("leashLength", Float.class);
                IEntityLeadExtension player1 = (IEntityLeadExtension) player;
                player1.setLeashLength(leashLength);
                player1.setLeadLengthSync(false);
                source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SET, player.getDisplayName(), leashLength), true);
            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };
        Command<CommandSourceStack> setRefPlayersLengthLeashLength = context -> {
            CommandSourceStack source = context.getSource();
            float leashLength = context.getArgument("leashLength", Float.class);
            try {
                Collection<ServerPlayer> playerCol = EntityArgument.getPlayers(context, "targetPlayers");
                playerCol.forEach(player -> {
                    try {
                        IEntityLeadExtension player1 = (IEntityLeadExtension) player;
                        player1.setLeashLength(leashLength);
                        player1.setLeadLengthSync(false);
                        source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SET, player.getDisplayName(), leashLength), true);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                });

            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };
        Command<CommandSourceStack> setRefEntitiesLengthLeashLength = context -> {
            CommandSourceStack source = context.getSource();
            float leashLength = context.getArgument("leashLength", Float.class);
            try {
                Collection<? extends Entity> entities = EntityArgument.getEntities(context, "targetEntities");
                entities.stream().filter(i->i instanceof Leashable).forEach(entity -> {
                    try {
                        IEntityLeadExtension iEntityLeadExtension = (IEntityLeadExtension) entity;
                        iEntityLeadExtension.setLeashLength(leashLength);
                        iEntityLeadExtension.setLeadLengthSync(false);
                        source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SET, entity.getDisplayName(), leashLength), true);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                });

            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };
        //获取Data 构造一个MutableComponent显示数据
        Command<CommandSourceStack> geSelfLeashData = context -> {
            CommandSourceStack source = context.getSource();
            try {
                ServerPlayer player = source.getPlayerOrException();
                Integer x = LeashLengthGetResultInt(player, source);
                if (x != null) return x;
            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };

        Command<CommandSourceStack> getRefPlayerLeashData = context -> {
            CommandSourceStack source = context.getSource();
            try {
                ServerPlayer player = EntityArgument.getPlayer(context, "targetPlayer");
                Integer x = LeashLengthGetResultInt(player, source);
                if (x != null) return x;
            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };
        Command<CommandSourceStack> getRefPlayersLeashData = context -> {
            CommandSourceStack source = context.getSource();
            try {
                Collection<ServerPlayer> playerCol = EntityArgument.getPlayers(context, "targetPlayers");
                playerCol.forEach(player -> {
                    try {
                        LeashLengthGetResultInt(player, source);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                });

            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };
        Command<CommandSourceStack> getRefEntitiesLeashData = context -> {
            CommandSourceStack source = context.getSource();
            try {
                Collection<? extends Entity> entities = EntityArgument.getEntities(context, "targetEntities");
                entities.stream().filter(i->i instanceof Leashable).forEach(entity -> {
                    try {
                        LeashLengthGetResultInt(entity, source);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                });

            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };
        //设置前要判断其实体距离（同一维度，且距离不得大于其绳长的1.2倍（待定，也许可以设置在配置文件里）
        Command<CommandSourceStack> setSelfLeashDataEntity = context -> {
            CommandSourceStack source = context.getSource();
            try {
                ServerPlayer player = source.getPlayerOrException();
                Integer x = LeashDataEntitySetResultInt(context, player, source);
                if (x != null) return x;

            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };


        Command<CommandSourceStack> setRefPlayerLeashDataEntity = context -> {
            CommandSourceStack source = context.getSource();
            try {
                ServerPlayer player = EntityArgument.getPlayer(context, "targetPlayer");
                Integer x = LeashDataEntitySetResultInt(context, player, source);
                if (x != null) return x;

            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };
        Command<CommandSourceStack> setRefPlayersLeashDataEntity = context -> {
            CommandSourceStack source = context.getSource();
            try {
                Collection<ServerPlayer> playerCol = EntityArgument.getPlayers(context, "targetPlayers");
                playerCol.forEach(player -> {
                    try {
                        LeashDataEntitySetResultInt(context, player, source);
                    } catch (CommandSyntaxException e) {
                        throw new RuntimeException(e);
                    }
                });
            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };
        Command<CommandSourceStack> setRefEntitiesLeashDataEntity = context -> {
            CommandSourceStack source = context.getSource();
            try {
                Collection<? extends Entity> entities = EntityArgument.getEntities(context, "targetEntities");
                entities.stream().filter(i->i instanceof Leashable).forEach(entity -> {
                    try {
                        LeashDataEntitySetResultInt(context, entity, source);
                    } catch (CommandSyntaxException e) {
                        throw new RuntimeException(e);
                    }
                });
            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };
        Command<CommandSourceStack> setSelfLeashDataByBlockPos = context -> {
            CommandSourceStack source = context.getSource();
            try {
                ServerPlayer player = source.getPlayerOrException();
                Integer x = LeashDataBlockPosSetResultInt(context, source, player);
                if (x != null) return x;


            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };
        Command<CommandSourceStack> setRefPlayerLeashDataByBlockPos = context -> {
            CommandSourceStack source = context.getSource();
            try {
                ServerPlayer player = EntityArgument.getPlayer(context, "targetPlayer");
                Integer x = LeashDataBlockPosSetResultInt(context, source, player);
                if (x != null) return x;

            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };
        Command<CommandSourceStack> setRefPlayersLeashDataByBlockPos = context -> {
            CommandSourceStack source = context.getSource();
            try {
                Collection<ServerPlayer> playerCol = EntityArgument.getPlayers(context, "targetPlayers");
                playerCol.forEach(player -> {
                    LeashDataBlockPosSetResultInt(context, source, player);
                });

            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };
        Command<CommandSourceStack> setRefEntitiesLeashDataByBlockPos = context -> {
            CommandSourceStack source = context.getSource();
            try {
                Collection<? extends Entity> entities = EntityArgument.getEntities(context, "targetEntities");
                entities.stream().filter(i->i instanceof Leashable).forEach(entity -> {
                    LeashDataBlockPosSetResultInt(context, source, entity);
                });

            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };

        Command<CommandSourceStack> clearSelfLeashData = context -> {
            CommandSourceStack source = context.getSource();
            try {
                ServerPlayer player = source.getPlayerOrException();
                Integer x = LeashDataClearResultInt(source, PlayerLeashable.getLeashDataEntity(player, source.getLevel()), player);
                if (x != null) return x;

            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };
        Command<CommandSourceStack> clearRefPlayerLeashData = context -> {
            CommandSourceStack source = context.getSource();
            try {
                ServerPlayer player = EntityArgument.getPlayer(context, "targetPlayer");
                Integer x = LeashDataClearResultInt(source, PlayerLeashable.getLeashDataEntity(player, source.getLevel()),player);
                if (x != null) return x;
            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };
        Command<CommandSourceStack> clearRefPlayersLeashData = context -> {
            CommandSourceStack source = context.getSource();
            try {
                Collection<ServerPlayer> playerCol = EntityArgument.getPlayers(context, "targetPlayers");
                playerCol.forEach(player -> {
                    try {
                        LeashDataClearResultInt(source, PlayerLeashable.getLeashDataEntity(player, source.getLevel()),player);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                });

            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };
        Command<CommandSourceStack> clearRefEntitiesLeashData = context -> {
            CommandSourceStack source = context.getSource();
            try {
                Collection<? extends Entity> entities = EntityArgument.getEntities(context, "targetEntities");
                entities.stream().filter(i->i instanceof Leashable).forEach(entity -> {
                    try {
                        LeashDataClearResultInt(source, PlayerLeashable.getLeashDataEntity(entity, source.getLevel()),entity);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                });

            } catch (Exception e) {
                source.sendFailure(Component.translatable(LEASH_FAILED));
                return -1;
            }
            return 0;
        };


        LiteralArgumentBuilder<CommandSourceStack> SelfLeashLength = $$leashRoot.then(Commands.literal("length").executes(getSelfLeashLength)
                .then(Commands.literal("get").executes(getSelfLeashLength))
                .then(Commands.literal("set").requires(cs -> cs.hasPermission(2))
                        .then(Commands.argument("leashLength", FloatArgumentType.floatArg(MIN_VALUE, MAX_VALUE)).executes(setSelfLengthLeashLength))
                )
        );

        LiteralArgumentBuilder<CommandSourceStack> RefEntitiesLeashLength = $$leashRoot.then(
                Commands.literal("length")
                        .then(Commands.argument("targetPlayer", EntityArgument.player()).executes(getRefPlayerLeashLength)
                                .then(Commands.literal("get").executes(getRefPlayerLeashLength))
                                .then(Commands.literal("set").requires(cs -> cs.hasPermission(2))
                                        .then(
                                                Commands.argument("leashLength", FloatArgumentType.floatArg(MIN_VALUE, MAX_VALUE)).executes(setRefPlayerLengthLeashLength)
                                        )
                                )
                        )
                        .then(Commands.argument("targetPlayers", EntityArgument.players()).executes(getRefPlayersLeashLength)
                                .then(Commands.literal("get").executes(getRefPlayersLeashLength))
                                .then(Commands.literal("set").requires(cs -> cs.hasPermission(2))
                                        .then(
                                                Commands.argument("leashLength", FloatArgumentType.floatArg(MIN_VALUE, MAX_VALUE)).executes(setRefPlayersLengthLeashLength)
                                        )
                                )
                        )
                        .then(Commands.argument("targetEntities", EntityArgument.entities()).executes(getRefEntitiesLeashLength)
                                .then(Commands.literal("get").executes(getRefEntitiesLeashLength))
                                .then(Commands.literal("set").requires(cs -> cs.hasPermission(2))
                                        .then(
                                                Commands.argument("leashLength", FloatArgumentType.floatArg(MIN_VALUE, MAX_VALUE)).executes(setRefEntitiesLengthLeashLength)
                                        )
                                )
                        )

        );

        LiteralArgumentBuilder<CommandSourceStack> RefEntitiesData = $$leashRoot.then(
                Commands.literal("data")
                        .then(Commands.argument("targetPlayer", EntityArgument.player()).executes(getRefPlayerLeashData)
                                .then(Commands.literal("get")
                                        .executes(getRefPlayerLeashData)
                                )
                                .then(Commands.literal("set").requires(cs -> cs.hasPermission(2))
                                        .then(Commands.argument("holderEntity", EntityArgument.entity())
                                                .executes(setRefPlayerLeashDataEntity)
                                        )
                                        .then(Commands.argument("BlockPos", BlockPosArgument.blockPos())
                                                .executes(setRefPlayerLeashDataByBlockPos)
                                        )
                                )
                                .then(Commands.literal("clear").requires(cs -> cs.hasPermission(2)).executes(clearRefPlayerLeashData))
                        )
                        .then(Commands.argument("targetPlayers", EntityArgument.players()).executes(getRefPlayersLeashData)
                                .then(Commands.literal("get")
                                        .executes(getRefPlayersLeashData)
                                )
                                .then(Commands.literal("set").requires(cs -> cs.hasPermission(2))
                                        .then(Commands.argument("holderEntity", EntityArgument.entity())
                                                .executes(setRefPlayersLeashDataEntity)
                                        )
                                        .then(Commands.argument("BlockPos", BlockPosArgument.blockPos())
                                                .executes(setRefPlayersLeashDataByBlockPos)
                                        )
                                )
                                .then(Commands.literal("clear").requires(cs -> cs.hasPermission(2)).executes(clearRefPlayersLeashData))
                        )
                        .then(Commands.argument("targetEntities", EntityArgument.entities()).executes(getRefEntitiesLeashData)
                                .then(Commands.literal("get")
                                        .executes(getRefEntitiesLeashData)
                                )
                                .then(Commands.literal("set").requires(cs -> cs.hasPermission(2))
                                        .then(Commands.argument("holderEntity", EntityArgument.entity())
                                                .executes(setRefEntitiesLeashDataEntity)
                                        )
                                        .then(Commands.argument("BlockPos", BlockPosArgument.blockPos())
                                                .executes(setRefEntitiesLeashDataByBlockPos)
                                        )
                                )
                                .then(Commands.literal("clear").requires(cs -> cs.hasPermission(2)).executes(clearRefEntitiesLeashData))
                        )
        );

        LiteralArgumentBuilder<CommandSourceStack> SelfData = $$leashRoot.then(
                Commands.literal("data")
                        .then(Commands.literal("get")
                                .executes(geSelfLeashData)
                        )
                        .then(Commands.literal("set").requires(cs -> cs.hasPermission(2))
                                .then(Commands.argument("holderEntity", EntityArgument.entity())
                                        .executes(setSelfLeashDataEntity)
                                )
                                .then(Commands.argument("BlockPos", BlockPosArgument.blockPos())
                                        .executes(setSelfLeashDataByBlockPos)
                                )
                        )
                        .then(Commands.literal("clear").requires(cs -> cs.hasPermission(2))
                                .executes(clearSelfLeashData)
                        )
        );

        if(shouldUsePrefix) {
            literalArgumentBuilder
                    .then(RefEntitiesLeashLength)
                    .then(SelfLeashLength)
                    .then(RefEntitiesData)
                    .then(SelfData);
            dispatcher.register(literalArgumentBuilder);
        } else {
            nodeList.forEach(dispatcher::register);
        }

    }

    private static @Nullable Integer LeashLengthGetResultInt(Entity entity, CommandSourceStack source) throws Exception {
        Leashable.LeashData leashDataFromEntityData;
        if(entity instanceof Leashable leashable)
            leashDataFromEntityData = leashable.getLeashData();
        else return null;
        if(leashDataFromEntityData == null) {
            source.sendSuccess(() -> Component.translatable(NO_LEASH_DATA, entity.getDisplayName()), true);
            return 1;
        } else {
            Entity leashDataEntity = PlayerLeashable.getLeashDataEntityOrThrown(leashDataFromEntityData, source.getLevel());
            source.sendSuccess(() -> Component.translatable(LEASH_DATA_SHOW, entity.getDisplayName(), leashDataEntity.getDisplayName()), true);
        }
        return null;
    }

    private static @Nullable Integer LeashDataBlockPosSetResultInt(CommandContext<CommandSourceStack> context, CommandSourceStack source, Entity entity) {
        BlockPos blockPos = BlockPosArgument.getBlockPos(context, "BlockPos");
        Entity leashDataEntity = PlayerLeashable.getLeashFenceKnotEntity(source.getLevel(), blockPos);
        Leashable leashedPlayer = (Leashable) entity;
        Component targetPlayerDisplayName = entity.getDisplayName();
        if(leashDataEntity == null) {
            ServerLevel level = context.getSource().getLevel();
            if(GameruleRegistry.getGameruleBoolValue(level,CreateLeashFenceKnotEntityIfAbsent.ID)) {
                if(level.getBlockState(blockPos).is(BlockTags.FENCES)) {
                    Entity leashKnotFence = PlayerLeashable.createLeashKnotFence(level, blockPos);
                    leashedPlayer.setLeashedTo(leashKnotFence, true);
                    source.sendSuccess(() -> Component.translatable(LEASH_DATA_SET, targetPlayerDisplayName, leashKnotFence.getDisplayName()), true);
                    return null;
                }
            }
            source.sendFailure(Component.translatable(LEASH_DATA_SET_FAILED_NO_KNOT_EXISTED_IN_THAT_POS, blockPos.getX(), blockPos.getY(), blockPos.getZ()));
            return 1;
        }
        Component leashDataEntityDisplayName = leashDataEntity.getDisplayName();

        return LeashDataCommonPartSetResultInt(source, entity, leashDataEntity, leashedPlayer, targetPlayerDisplayName, leashDataEntityDisplayName);
    }

    private static @Nullable Integer LeashDataEntitySetResultInt(CommandContext<CommandSourceStack> context, Entity entity, CommandSourceStack source) throws CommandSyntaxException {
        Entity leashDataEntity = EntityArgument.getEntity(context, "holderEntity");
        Leashable leashable = (Leashable) entity;
        Component targetPlayerDisplayName = entity.getDisplayName();
        Component leashDataEntityDisplayName = leashDataEntity.getDisplayName();
        if(entity.equals(leashDataEntity)) {
            source.sendFailure(Component.translatable(LEASH_DATA_SET_FAILED_FORBID_SAME_ENTITY));
            return 1;
        }
        return LeashDataCommonPartSetResultInt(source, entity, leashDataEntity, leashable, targetPlayerDisplayName, leashDataEntityDisplayName);
    }

    private static @Nullable Integer LeashDataCommonPartSetResultInt(CommandSourceStack source, Entity entity, Entity leashDataEntity, Leashable leashable, Component targetPlayerDisplayName, Component leashDataEntityDisplayName) {
        if(entity.level() != leashDataEntity.level()) {
            source.sendFailure(Component.translatable(LEASH_DATA_SET_FAILED_DIFF_LEVEL, targetPlayerDisplayName, leashDataEntityDisplayName));
            return 2;
        }
        IEntityLeadExtension targetPlayerExtension = (IEntityLeadExtension) entity;
        if (entity.distanceTo(leashDataEntity) > targetPlayerExtension.getLeashLength() * LeashedPlayer.M1()) {
            source.sendFailure(Component.translatable(LEASH_DATA_SET_FAILED_TOO_FAR, targetPlayerDisplayName, leashDataEntityDisplayName, targetPlayerExtension.getLeashLength()));
            return 3;
        }
        leashable.setLeashedTo(leashDataEntity, true);
        source.sendSuccess(() -> Component.translatable(LEASH_DATA_SET, targetPlayerDisplayName, leashDataEntityDisplayName), true);
        return null;
    }

    private static @Nullable Integer LeashDataClearResultInt(CommandSourceStack source, Entity leashDataEntity, Entity entity) {
       if(leashDataEntity == null) {
           source.sendFailure(Component.translatable(LEASH_DATA_CLEAR_FAILED_NO_DATA, entity.getDisplayName()));
           return 1;
       }
        Leashable.dropLeash((Entity & Leashable) entity, true, false);
        source.sendSuccess(() -> Component.translatable(LEASH_DATA_CLEAR, entity.getDisplayName(), leashDataEntity.getDisplayName()), true);
        return null;
    }


}
