package com.teamwizardry.wizardry.common.entity.ai;

import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.ai.EntityAIBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.pathfinding.PathNavigate;
import net.minecraft.pathfinding.PathNavigateGround;
import net.minecraft.pathfinding.PathNodeType;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;

import javax.annotation.Nullable;
import java.util.UUID;

public class EntityAIFollowPlayer extends EntityAIBase {

	private final EntityLiving entity;
	private final double followSpeed;
	private final PathNavigate petPathfinder;
	private World world;
	private float maxDist;
	private float minDist;
	@Nullable
	private EntityLivingBase owner;
	private int timeToRecalcPath;
	private float oldWaterCost;

	public EntityAIFollowPlayer(EntityLiving entity, double followSpeedIn, float minDistIn, float maxDistIn) {
		this.entity = entity;
		this.world = entity.world;
		this.followSpeed = followSpeedIn;
		this.petPathfinder = entity.getNavigator();
		this.minDist = minDistIn;
		this.maxDist = maxDistIn;
		this.setMutexBits(3);

		UUID exclude = entity.getEntityData().getUniqueId("owner");
		if (exclude != null) {
			EntityPlayer owner = world.getPlayerEntityByUUID(exclude);
			if (owner != null) {
				this.owner = owner;
			}
		}

		if (!(entity.getNavigator() instanceof PathNavigateGround)) {
			throw new IllegalArgumentException("Unsupported mob type for FollowOwnerGoal");
		}
	}

	/**
	 * Returns whether the EntityAIBase should begin execution.
	 */
	@Override
	public boolean shouldExecute() {
		EntityLivingBase entitylivingbase = owner;

		if (entitylivingbase == null) {
			return false;
		} else if (entitylivingbase instanceof EntityPlayer && ((EntityPlayer) entitylivingbase).isSpectator()) {
			return false;
		} else if (this.entity.getDistance(entitylivingbase) < this.minDist) {
			return false;
		} else {
			this.owner = entitylivingbase;
			return true;
		}
	}

	/**
	 * Returns whether an in-progress EntityAIBase should continue executing
	 */
	@Override
	public boolean shouldContinueExecuting() {
		return !this.petPathfinder.noPath() && (this.owner != null && this.entity.getDistance(this.owner) > this.maxDist);
	}

	/**
	 * Execute a one shot task or start executing a continuous task
	 */
	@Override
	public void startExecuting() {
		this.timeToRecalcPath = 0;
		this.oldWaterCost = this.entity.getPathPriority(PathNodeType.WATER);
		this.entity.setPathPriority(PathNodeType.WATER, 0.0F);
	}

	/**
	 * Reset the task's internal state. Called when this task is interrupted by another one
	 */
	@Override
	public void resetTask() {
		this.owner = null;
		this.petPathfinder.clearPath();
		this.entity.setPathPriority(PathNodeType.WATER, this.oldWaterCost);
	}

	private boolean isEmptyBlock(BlockPos pos) {
		IBlockState iblockstate = this.world.getBlockState(pos);
		return iblockstate.getMaterial() == Material.AIR || !iblockstate.isFullCube();
	}

	/**
	 * Keep ticking a continuous task that has already been started
	 */
	@SuppressWarnings("deprecation")
	@Override
	public void updateTask() {
		if (this.owner == null) return;
		this.entity.getLookHelper().setLookPositionWithEntity(this.owner, 10.0F, (float) this.entity.getVerticalFaceSpeed());

		if (--this.timeToRecalcPath <= 0) {
			this.timeToRecalcPath = 10;

			if (!this.petPathfinder.tryMoveToEntityLiving(this.owner, this.followSpeed)) {
				if (!this.entity.getLeashed()) {
					if (this.entity.getDistance(this.owner) >= 12.0D) {
						int i = MathHelper.floor(this.owner.posX) - 2;
						int j = MathHelper.floor(this.owner.posZ) - 2;
						int k = MathHelper.floor(this.owner.getEntityBoundingBox().minY);

						for (int l = 0; l <= 4; ++l) {
							for (int i1 = 0; i1 <= 4; ++i1) {
								if ((l < 1 || i1 < 1 || l > 3 || i1 > 3) && this.world.getBlockState(new BlockPos(i + l, k - 1, j + i1)).isTopSolid() && this.isEmptyBlock(new BlockPos(i + l, k, j + i1)) && this.isEmptyBlock(new BlockPos(i + l, k + 1, j + i1))) {
									this.entity.setLocationAndAngles((double) ((float) (i + l) + 0.5F), (double) k, (double) ((float) (j + i1) + 0.5F), this.entity.rotationYaw, this.entity.rotationPitch);
									this.petPathfinder.clearPath();
									return;
								}
							}
						}
					}
				}
			}
		}
	}
}