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

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import net.minecraft.entity.EntityCreature;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.ai.EntityAINearestAttackableTarget;
import net.minecraft.entity.ai.EntityAITarget;
import net.minecraft.entity.monster.EntityCreeper;
import net.minecraft.entity.monster.EntitySkeleton;
import net.minecraft.entity.monster.EntityZombie;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Items;
import net.minecraft.inventory.EntityEquipmentSlot;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EntitySelectors;
import net.minecraft.util.math.AxisAlignedBB;

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

public class EntityAINearestAttackableTargetFiltered<T extends EntityLivingBase> extends EntityAITarget {
	protected final Class<T> targetClass;
	/**
	 * Instance of EntityAINearestAttackableTargetSorter.
	 */
	protected final EntityAINearestAttackableTarget.Sorter sorter;
	protected final Predicate<? super T> targetEntitySelector;
	private final int targetChance;
	protected T targetEntity;

	public EntityAINearestAttackableTargetFiltered(EntityCreature creature, Class<T> classTarget, boolean checkSight) {
		this(creature, classTarget, checkSight, false);
	}

	public EntityAINearestAttackableTargetFiltered(EntityCreature creature, Class<T> classTarget, boolean checkSight, boolean onlyNearby) {
		this(creature, classTarget, 10, checkSight, onlyNearby, null);
	}

	public EntityAINearestAttackableTargetFiltered(EntityCreature creature, Class<T> classTarget, int chance, boolean checkSight, boolean onlyNearby, @Nullable final Predicate<? super T> targetSelector) {
		super(creature, checkSight, onlyNearby);
		this.targetClass = classTarget;
		this.targetChance = chance;
		this.sorter = new EntityAINearestAttackableTarget.Sorter(creature);
		this.setMutexBits(1);

		UUID exclude = creature.getEntityData().getUniqueId("owner");

		this.targetEntitySelector = (Predicate<T>) entity -> (entity != null && !entity.getUniqueID().equals(exclude)) && (targetSelector == null || targetSelector.apply(entity) && (EntitySelectors.NOT_SPECTATING.apply(entity) && EntityAINearestAttackableTargetFiltered.this.isSuitableTarget(entity, false)));
	}

	/**
	 * Returns whether the EntityAIBase should begin execution.
	 */
	@SuppressWarnings("unchecked")
	public boolean shouldExecute() {
		if (this.targetChance > 0 && this.taskOwner.getRNG().nextInt(this.targetChance) != 0) {
			return false;
		} else if (this.targetClass != EntityPlayer.class && this.targetClass != EntityPlayerMP.class) {
			List<T> list = this.taskOwner.world.getEntitiesWithinAABB(this.targetClass, this.getTargetableArea(this.getTargetDistance()), this.targetEntitySelector);

			if (list.isEmpty()) {
				return false;
			} else {
				list.sort(this.sorter);
				this.targetEntity = list.get(0);
				return true;
			}
		} else {
			this.targetEntity = (T) this.taskOwner.world.getNearestAttackablePlayer(this.taskOwner.posX, this.taskOwner.posY + (double) this.taskOwner.getEyeHeight(), this.taskOwner.posZ, this.getTargetDistance(), this.getTargetDistance(), new Function<EntityPlayer, Double>() {
				@Nullable
				public Double apply(@Nullable EntityPlayer p_apply_1_) {
					ItemStack itemstack = p_apply_1_.getItemStackFromSlot(EntityEquipmentSlot.HEAD);

					if (itemstack.getItem() == Items.SKULL) {
						int i = itemstack.getItemDamage();
						boolean flag = EntityAINearestAttackableTargetFiltered.this.taskOwner instanceof EntitySkeleton && i == 0;
						boolean flag1 = EntityAINearestAttackableTargetFiltered.this.taskOwner instanceof EntityZombie && i == 2;
						boolean flag2 = EntityAINearestAttackableTargetFiltered.this.taskOwner instanceof EntityCreeper && i == 4;

						if (flag || flag1 || flag2) {
							return Double.valueOf(0.5D);
						}
					}

					return Double.valueOf(1.0D);
				}
			}, (Predicate<EntityPlayer>) this.targetEntitySelector);
			return this.targetEntity != null;
		}
	}

	protected AxisAlignedBB getTargetableArea(double targetDistance) {
		return this.taskOwner.getEntityBoundingBox().grow(targetDistance, 4.0D, targetDistance);
	}

	/**
	 * Execute a one shot task or start executing a continuous task
	 */
	public void startExecuting() {
		this.taskOwner.setAttackTarget(this.targetEntity);
		super.startExecuting();
	}

}