package common.entity.npc;

import java.util.List;
import java.util.function.Predicate;

import common.ai.EntityAIMoveThroughVillage;
import common.attributes.AttributeModifier;
import common.attributes.Attributes;
import common.entity.DamageSource;
import common.entity.animal.EntityChicken;
import common.entity.types.EntityLiving;
import common.init.Config;
import common.rng.Random;
import common.util.BlockPos;
import common.util.ExtMath;
import common.world.World;
import common.world.AWorldServer;

public class EntityZombie extends EntityNPC
{
    public EntityZombie(World worldIn)
    {
        super(worldIn);
        this.tasks.addTask(6, new EntityAIMoveThroughVillage(this, 1.0D, false));
    }

    protected void applyEntityAttributes()
    {
        super.applyEntityAttributes();
        this.getEntityAttribute(Attributes.FOLLOW_RANGE).setBaseValue(28.0D);
        this.getEntityAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(0.23000000417232513D);
        this.getEntityAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(3.0D);
        this.getAttributeMap().registerAttribute(Attributes.REINFORCEMENT_CHANCE).setBaseValue(this.rand.doublev() * 0.10000000149011612D);
    }
    
    public void onLivingUpdate()
    {
        if(this.isRiding() && this.getAttackTarget() != null && this.vehicle instanceof EntityChicken)
            ((EntityLiving)this.vehicle).getNavigator().setPath(this.getNavigator().getPath(), 1.5D);
        if(!this.worldObj.client)
        	this.setAttacking(this.getAttackTarget() != null);
        super.onLivingUpdate();
    }
    
    public boolean attackEntityFrom(DamageSource source, int amount)
    {
        if (super.attackEntityFrom(source, amount))
        {
            EntityLiving entitylivingbase = this.getAttackTarget();

            if (entitylivingbase == null && source.getEntity() instanceof EntityLiving)
            {
                entitylivingbase = (EntityLiving)source.getEntity();
            }

            if (entitylivingbase != null && /* this.worldObj.getDifficulty() == Difficulty.HARD && */ (double)this.rand.floatv() < this.getEntityAttribute(Attributes.REINFORCEMENT_CHANCE).getAttributeValue() && Config.mobs && Config.spawnMoreZombie)
            {
                int i = ExtMath.floord(this.posX);
                int j = ExtMath.floord(this.posY);
                int k = ExtMath.floord(this.posZ);
                EntityZombie entityzombie = new EntityZombie(this.worldObj);

                for (int l = 0; l < 50; ++l)
                {
                    int i1 = i + this.rand.range(7, 40) * this.rand.range(-1, 1);
                    int j1 = j + this.rand.range(7, 40) * this.rand.range(-1, 1);
                    int k1 = k + this.rand.range(7, 40) * this.rand.range(-1, 1);

                    if (this.worldObj.isBlockSolid(new BlockPos(i1, j1 - 1, k1)) && this.worldObj.getLightFromNeighbors(new BlockPos(i1, j1, k1)) < 10)
                    {
                        entityzombie.setPosition((double)i1, (double)j1, (double)k1);

                        if (!this.worldObj.isAnyPlayerWithinRangeAt((double)i1, (double)j1, (double)k1, 7.0D) && this.worldObj.checkNoEntityCollision(entityzombie.getEntityBoundingBox(), entityzombie) && this.worldObj.getCollidingBoundingBoxes(entityzombie, entityzombie.getEntityBoundingBox()).isEmpty() && !this.worldObj.isAnyLiquid(entityzombie.getEntityBoundingBox()))
                        {
                            this.worldObj.spawnEntityInWorld(entityzombie);
                            entityzombie.setAttackTarget(entitylivingbase);
                            entityzombie.onInitialSpawn(null);
                            this.getEntityAttribute(Attributes.REINFORCEMENT_CHANCE).applyModifier(new AttributeModifier("Zombie reinforcement caller charge", -0.05000000074505806D, false));
                            entityzombie.getEntityAttribute(Attributes.REINFORCEMENT_CHANCE).applyModifier(new AttributeModifier("Zombie reinforcement callee charge", -0.05000000074505806D, false));
                            break;
                        }
                    }
                }
            }

            return true;
        }
        else
        {
            return false;
        }
    }

//    public boolean attackEntityAsMob(Entity entityIn)
//    {
//        boolean flag = super.attackEntityAsMob(entityIn);
//
//        if (flag)
//        {
//            int i = this.worldObj.getDifficulty().getId();
//
//            if (this.getHeldItem() == null && this.isBurning() && this.rand.floatv() < (float)i * 0.3F)
//            {
//                entityIn.setFire(2 * i);
//            }
//        }
//
//        return flag;
//    }

//    /**
//     * Returns the sound this mob makes while it's alive.
//     */
//    protected String getLivingSound()
//    {
//        return "mob.zombie.say";
//    }
//
//    /**
//     * Returns the sound this mob makes when it is hurt.
//     */
//    protected String getHurtSound()
//    {
//        return "mob.zombie.hurt";
//    }
//
//    /**
//     * Returns the sound this mob makes on death.
//     */
//    protected String getDeathSound()
//    {
//        return "mob.zombie.death";
//    }
//
//    protected void playStepSound(BlockPos pos, Block blockIn)
//    {
//        this.playSound("mob.zombie.step", 0.15F, 1.0F);
//    }
    
    public void onKillEntity(EntityLiving entityLivingIn)
    {
        super.onKillEntity(entityLivingIn);

        if (/* (this.worldObj.getDifficulty() == Difficulty.NORMAL || this.worldObj.getDifficulty() == Difficulty.HARD) && */ entityLivingIn instanceof EntityNPC && !(entityLivingIn.isPlayer()) && Config.convertZombie)
        {
//            if (this.worldObj.getDifficulty() != Difficulty.HARD && this.rand.chance())
//            {
//                return;
//            }

        	EntityNPC entityliving = (EntityNPC)entityLivingIn;
            EntityZombie entityzombie = new EntityZombie(this.worldObj);
            entityzombie.copyLocationAndAnglesFrom(entityLivingIn);
            this.worldObj.removeEntity(entityLivingIn);
            entityzombie.onInitialSpawn(null);
//            entityzombie.setVillager(true);

//            if(entityLivingIn instanceof EntityNPC) {
            entityzombie.setGrowingAge(entityliving.getGrowingAge());
//            }
//            else if (entityLivingIn.isChild()) {
//                entityzombie.setGrowingAge(-24000);
//            }

//            entityzombie.setNoAI(entityliving.isAIDisabled());

            if (entityliving.hasCustomName())
            {
                entityzombie.setCustomNameTag(entityliving.getCustomNameTag());
//                entityzombie.setAlwaysRenderNameTag(entityliving.getAlwaysRenderNameTag());
            }

            this.worldObj.spawnEntityInWorld(entityzombie);
            this.worldObj.playAuxSFX(1016, new BlockPos((int)this.posX, (int)this.posY, (int)this.posZ), 0);
        }
    }

//    protected boolean canPickUpItem(ItemStack stack)
//    {
//        return stack.getItem() == Items.egg && this.isRiding() ? false : super.canPickUpItem(stack);
//    }

    /**
     * Called only once on an entity when first time spawned, via egg, mob spawner, natural spawning etc, but not called
     * when entity is reloaded from nbt. Mainly used for initializing attributes and inventory
     */
    public Object onInitialSpawn(Object livingdata)
    {
        livingdata = super.onInitialSpawn(livingdata);
//        float f = difficulty.getDifficulty();
//        this.setCanPickUpLoot(this.rand.floatv() < 0.55F * f);

        if (livingdata == null)
        {
            livingdata = new EntityZombie.GroupData(this.worldObj.rand.floatv() < 0.05F); //, this.worldObj.rand.floatv() < 0.05F);
        }

        if (livingdata instanceof EntityZombie.GroupData)
        {
            EntityZombie.GroupData entityzombie$groupdata = (EntityZombie.GroupData)livingdata;

//            if (entityzombie$groupdata.isVillager)
//            {
//                this.setVillager(true);
//            }

            if (entityzombie$groupdata.isChild)
            {
                this.setGrowingAge(-24000);

                if ((double)this.worldObj.rand.floatv() < 0.05D)
                {
                    List<EntityChicken> list = this.worldObj.<EntityChicken>getEntitiesWithinAABB(EntityChicken.class, this.getEntityBoundingBox().expand(5.0D, 3.0D, 5.0D), new Predicate<EntityChicken>() {
                        public boolean test(EntityChicken entity) {
                            return entity.isEntityAlive() && entity.passenger == null && entity.vehicle == null;
                        }
                    });

                    if (!list.isEmpty())
                    {
                        EntityChicken entitychicken = (EntityChicken)list.get(0);
                        entitychicken.setChickenJockey(true);
                        this.mountEntity(entitychicken);
                    }
                }
                else if ((double)this.worldObj.rand.floatv() < 0.05D)
                {
                    EntityChicken entitychicken1 = new EntityChicken(this.worldObj);
                    entitychicken1.setLocationAndAngles(this.posX, this.posY, this.posZ, this.rotYaw, 0.0F);
                    entitychicken1.onInitialSpawn(null);
                    entitychicken1.setChickenJockey(true);
                    this.worldObj.spawnEntityInWorld(entitychicken1);
                    this.mountEntity(entitychicken1);
                }
            }
        }

//        this.setBreakDoorsAItask(this.rand.floatv() < f * 0.1F);
//        this.setEquipmentBasedOnDifficulty(difficulty);
//        this.setEnchantmentBasedOnDifficulty(difficulty);

//        if (Config.useHalloween && this.getItem(4) == null)
//        {
//            Calendar calendar = World.getCurrentDate();
//
//            if (calendar.get(2) + 1 == 10 && calendar.get(5) == 31 && this.rand.floatv() < 0.25F)
//            {
//                this.setItem(4, new ItemStack(this.rand.floatv() < 0.1F ? Blocks.lit_pumpkin : Blocks.pumpkin));
//                this.dropChances[4] = 0.0F;
//            }
//        }

        this.getEntityAttribute(Attributes.KNOCKBACK_RESISTANCE).applyModifier(new AttributeModifier("Random spawn bonus", this.rand.doublev() * 0.05000000074505806D, false));
        double d0 = this.rand.doublev() * 15.0;

        if (d0 > 1.0D)
        {
            this.getEntityAttribute(Attributes.FOLLOW_RANGE).applyModifier(new AttributeModifier("Random zombie-spawn bonus", d0, false));
        }

        if (this.rand.chance(30))
        {
            this.getEntityAttribute(Attributes.REINFORCEMENT_CHANCE).applyModifier(new AttributeModifier("Leader zombie bonus", this.rand.doublev() * 0.25D + 0.5D, false));
            this.getEntityAttribute(Attributes.MAX_HEALTH).applyModifier(new AttributeModifier("Leader zombie bonus", this.rand.roll(4), true));
//            this.setBreakDoorsAItask(true);
        }

        return livingdata;
    }
    
	public int getColor() {
		return 0xff0000;
	}

//	public boolean isAggressive() {
//		return true;
//	}
//
//	public boolean isPeaceful() {
//		return false;
//	}

	public boolean isAggressive(Class<? extends EntityNPC> clazz) {
		return clazz == EntityHuman.class || clazz == EntityElf.class;
	}

	public boolean isPeaceful(Class<? extends EntityNPC> clazz) {
		return clazz == EntityCultivator.class;
	}

//	public boolean canInfight(Alignment align) {
//		return false;
//	}
//
//	public boolean canMurder(Alignment align) {
//		return false;
//	}

//	public boolean canUseMagic() {
//		return false;
//	}

	public int getBaseHealth(Random rand) {
		return rand.range(16, 36);
	}

//	public int getBaseEnergy(Random rand) {
//		return 0;
//	}

    public float getHeightDeviationMin() {
    	return -0.2f;
    }

    public float getHeightDeviationMax() {
    	return 0.2f;
    }
    
    public float getSpeciesBaseSize() {
    	return 1.8f;
    }

	public Alignment getNaturalAlign() {
		return rand.pick(Alignment.CHAOTIC_EVIL, Alignment.EVIL);
	}

	public boolean getCanSpawnHere() {
		return !((AWorldServer)this.worldObj).isDaytime();
	}
    
//    public boolean canAmbush(EntityLiving entity) {
//    	return true;
//    }
    
    public boolean arePotionsInverted() {
        return true;
    }
    
    public boolean hasArmsRaised() {
        return this.isAttacking();
    }

    class GroupData
    {
        public boolean isChild;

        private GroupData(boolean isBaby)
        {
            this.isChild = isBaby;
        }
    }
}
