package com.r3944realms.leashedplayer.utils;

import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.content.gamerules.Gamerules;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.*;
import net.neoforged.fml.loading.FMLPaths;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;

import static com.r3944realms.leashedplayer.utils.Logger.logger;

public class Util {
    public static String getGameruleName(Class<?> clazz) {
        return Gamerules.GAMERULE_PREFIX + clazz.getSimpleName();
    }
    public static String getGameruleName(String gamerulesName) {
        return Gamerules.GAMERULE_PREFIX + gamerulesName;
    }

    public static void configFileCreate(String[] children) {//初始化配置文件目录
        File configFile = new File(FMLPaths.CONFIGDIR.get().toFile(), LeashedPlayer.MOD_ID);
        if (!configFile.exists()) {
            boolean mkdirSuccess = configFile.mkdirs();
            if (!mkdirSuccess) {
                logger.error("failed to create config directory for whimsicality");
                throw new RuntimeException("failed to create config directory for " + LeashedPlayer.MOD_ID);
            } else {
                for (String child : children) {
                    File file = new File(configFile, child);
                    if (!file.exists()) {
                        boolean mkdirChildrenSuccess = file.mkdirs();
                        if (!mkdirChildrenSuccess) {
                            logger.error("failed to create {} directory for +" + LeashedPlayer.MOD_ID, child);
                            throw new RuntimeException("failed to create " + child + " directory for" +LeashedPlayer.MOD_ID);
                        }
                    }
                }
            }
        }
    }
    public static void throwItemTowardsLook(Entity thrower, Item itemToThrow, float velocity, float inaccuracy) {
        ItemEntity thrownItem = new ItemEntity(
                thrower.level(),
                thrower.getX(),
                thrower.getEyeY() - 0.1,
                thrower.getZ(),
                new ItemStack(itemToThrow)
        );
        thrownItem.setPickUpDelay(40);
        Vec3 lookDirection = thrower.getLookAngle();

        thrownItem.setDeltaMovement(
                lookDirection.x * velocity + (thrower.level().random.nextGaussian() * 0.0075 * inaccuracy),
                lookDirection.y * velocity + (thrower.level().random.nextGaussian() * 0.0075 * inaccuracy),
                lookDirection.z * velocity + (thrower.level().random.nextGaussian() * 0.0075 * inaccuracy)
        );

        thrower.level().addFreshEntity(thrownItem);
    }

    public static List<HitResult> getRefLookAtEntityHitResult(Entity looker, Level level, float distance, Function<Entity, Boolean> condition) {
        Vec3 startPosition = looker.getEyePosition();
        Vec3 endPosition = looker.getLookAngle().normalize().scale(distance).add(startPosition);
        BlockHitResult clip = level.clip(new ClipContext(startPosition, endPosition, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, looker));
        endPosition = clip.getLocation();
        AABB range = looker.getBoundingBox().expandTowards(endPosition.subtract(startPosition));
        List<HitResult> hits = new ArrayList<>();
        List<? extends Entity> entities = level.getEntities(looker, range, condition::apply);
        for (Entity entity : entities) {
            Vec3 vec3 = entity.getBoundingBox().clip(startPosition, endPosition).orElse(null);
            if(vec3 != null) {
                EntityHitResult entityHitResult = new EntityHitResult(entity, vec3);
                hits.add(entityHitResult);
            }
        }
        return hits;
    }

    @Nullable
    public static Entity getTheNearestEntityFromHitResultList(Entity looker, List<HitResult> hitResults) {
        if(!hitResults.isEmpty()) {
            hitResults.sort(Comparator.comparingDouble(e -> e.getLocation().distanceTo(looker.getEyePosition())));
            HitResult hitResult = hitResults.getFirst();
            if (hitResult instanceof EntityHitResult entityHitResult)
                return entityHitResult.getEntity();
            else return null;
        }
        else return null;
    }
    /**
     * 刹车（
     * @param pEntity 刹车的实体
     * @param pMaxX X方向的最大动量
     * @param pMaxY Y方向的最大动量
     * @param pMaxZ Z方向的最大动量
     */
    public static void MovementBrake(Entity pEntity, double pMaxX, double pMaxY, double pMaxZ) {
        Vec3 deltaMovement = pEntity.getDeltaMovement();
        double dX = Math.abs(deltaMovement.x) > pMaxX ? 0 : deltaMovement.x;
        double dY = Math.abs(deltaMovement.y) > pMaxY ? 0 : deltaMovement.y;
        double dZ = Math.abs(deltaMovement.z) > pMaxZ ? 0 : deltaMovement.z;
        pEntity.setDeltaMovement(dX, dY,dZ);
        pEntity.hurtMarked = true;
    }
    /**
     * 刹车（
     * @param pEntity 刹车的实体
     * @param pOpt 自定义规则
     */
    public static void MovementBrake(Entity pEntity, @javax.annotation.Nullable Consumer<Entity> pOpt) {
        Consumer<Entity> consumer = pOpt;
        if(pOpt == null) {
            consumer = entity -> {
                Vec3 deltaMovement = entity.getDeltaMovement();
                double dX = Math.abs(deltaMovement.x) > 1 ? 0 : deltaMovement.x;
                double dY = Math.abs(deltaMovement.y) > 1 ? 0 : deltaMovement.y;
                double dZ = Math.abs(deltaMovement.z) > 1 ? 0 : deltaMovement.z;
                entity.setDeltaMovement(dX, dY,dZ);
                entity.hurtMarked = true;
            };
        }
        consumer.accept(pEntity);
    }
}
