package com.legacy.aether.entities.passive.mountable;

import net.minecraft.block.Block;
import net.minecraft.entity.EntityAgeable;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.EntityAILookIdle;
import net.minecraft.entity.ai.EntityAIMate;
import net.minecraft.entity.ai.EntityAISwimming;
import net.minecraft.entity.ai.EntityAIWander;
import net.minecraft.entity.ai.EntityAIWatchClosest;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;

import com.legacy.aether.api.AetherAPI;
import com.legacy.aether.api.moa.AetherMoaType;
import com.legacy.aether.entities.util.EntitySaddleMount;
import com.legacy.aether.items.ItemMoaEgg;
import com.legacy.aether.items.ItemsAether;

public class EntityMoa extends EntitySaddleMount {

    public float wingRotation, destPos, prevDestPos, prevWingRotation;

    protected int ticksOffGround, ticksUntilFlap, secsUntilFlying, secsUntilWalking, secsUntilHungry, secsUntilEgg;

    public EntityMoa(World world) {
        super(world);

        this.initAI();

        this.setSize(1.0F, 2.0F);
        this.stepHeight = 1.0F;

        this.secsUntilEgg = this.getRandomEggTime();
    }

    public EntityMoa(World world, AetherMoaType type) {
        this(world);

        this.setMoaType(type);
    }

    @Override
    public void moveEntity(double x, double y, double z) {
        if (!this.isSitting()) {
            super.moveEntity(x, y, z);
        } else {
            super.moveEntity(0, y, 0);
        }
    }

    public int getRandomEggTime() {
        return 775 + this.rand.nextInt(50);
    }

    public void initAI() {
        this.tasks.addTask(0, new EntityAISwimming(this));
        this.tasks.addTask(2, new EntityAIWander(this, 0.30F));
        this.tasks.addTask(4, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F));
        this.tasks.addTask(5, new EntityAILookIdle(this));
        this.tasks.addTask(6, new EntityAIMate(this, 0.25F));
    }

    @Override
    public void entityInit() {
        super.entityInit();

        AetherMoaType moaType = AetherAPI.instance().getRandomMoaType();

        this.dataWatcher.addObject(20, new Short((short) AetherAPI.instance().getMoaTypeId(moaType)));
        this.dataWatcher.addObject(21, new Byte((byte) moaType.getMoaProperties().getMaxJumps()));
        this.dataWatcher.addObject(22, new Byte((byte) 0));
        this.dataWatcher.addObject(23, new Byte((byte) 0));
        this.dataWatcher.addObject(24, new Byte((byte) 0));
        this.dataWatcher.addObject(25, new Byte((byte) 0));

    }

    @Override
    public boolean isAIEnabled() {
        return true;
    }

    @Override
    protected void applyEntityAttributes() {
        super.applyEntityAttributes();

        this.getEntityAttribute(SharedMonsterAttributes.maxHealth).setBaseValue(10.0D);
        this.getEntityAttribute(SharedMonsterAttributes.movementSpeed).setBaseValue(1.0D);
    }

    public boolean isSitting() {
        return this.dataWatcher.getWatchableObjectByte(25) == (byte) 1;
    }

    public void setSitting(boolean isSitting) {
        this.dataWatcher.updateObject(25, (byte) (isSitting ? 1 : 0));
    }

    public boolean isHungry() {
        return this.dataWatcher.getWatchableObjectByte(24) == (byte) 1;
    }

    public void setHungry(boolean hungry) {
        this.dataWatcher.updateObject(24, (byte) (hungry ? 1 : 0));
    }

    public byte getAmountFed() {
        return this.dataWatcher.getWatchableObjectByte(23);
    }

    public void setAmountFed(int amountFed) {
        this.dataWatcher.updateObject(23, (byte) amountFed);
    }

    public void increaseAmountFed(int amountFed) {
        int amount = (int) this.getAmountFed();

        this.setAmountFed(amount + amountFed);
    }

    public boolean isPlayerGrown() {
        return this.dataWatcher.getWatchableObjectByte(22) == (byte) 1;
    }

    public void setPlayerGrown(boolean playerGrown) {
        this.dataWatcher.updateObject(22, (byte) (playerGrown ? 1 : 0));
    }

    public int getMaxJumps() {
        return this.getMoaType().getMoaProperties().getMaxJumps();
    }

    public int getRemainingJumps() {
        return (int) this.dataWatcher.getWatchableObjectByte(21);
    }

    public void setRemainingJumps(int jumps) {
        this.dataWatcher.updateObject(21, (byte) jumps);
    }

    public int getMoaTypeId() {
        return (int) this.dataWatcher.getWatchableObjectShort(20);
    }

    public AetherMoaType getMoaType() {
        int id = (int) this.dataWatcher.getWatchableObjectShort(20);

        return AetherAPI.instance().getMoaType(id);
    }

    public void setMoaType(AetherMoaType type) {
        this.dataWatcher.updateObject(20, new Short((short) AetherAPI.instance().getMoaTypeId(type)));
        this.dataWatcher.updateObject(21, new Byte((byte) type.getMoaProperties().getMaxJumps()));
    }

    @Override
    public void onUpdate() {
        super.onUpdate();

        if (this.isJumping) {
            this.motionY += 0.05F;
        }

        this.updateWingRotation();
        this.fall();

        if (this.secsUntilHungry > 0) {
            if (this.ticksExisted % 20 == 0) {
                this.secsUntilHungry--;
            }
        } else if (!this.isHungry()) {
            this.setHungry(true);
        }

        if (!this.worldObj.isRemote && !this.isChild() && this.riddenByEntity == null) {
            if (this.secsUntilEgg > 0) {
                if (this.ticksExisted % 20 == 0) {
                    this.secsUntilEgg--;
                }
            } else {
                this.playSound("mob.chicken.plop", 1.0F, (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F);
                this.entityDropItem(ItemMoaEgg.getStackFromType(this.getMoaType()), 0);

                this.secsUntilEgg = this.getRandomEggTime();
            }
        }

        this.fallDistance = 0.0F;
    }

    public void resetHunger() {
        if (!this.worldObj.isRemote) {
            this.setHungry(false);
        }

        this.secsUntilHungry = 40 + this.rand.nextInt(40);
    }

    public void updateWingRotation() {
        if (!this.onGround) {
            if (this.ticksUntilFlap == 0) {
                this.worldObj.playSoundAtEntity(this, "mob.bat.takeoff", 0.15F, MathHelper.clamp_float(this.rand.nextFloat(), 0.7f, 1.0f) + MathHelper.clamp_float(this.rand.nextFloat(), 0f, 0.3f));

                this.ticksUntilFlap = 8;
            } else {
                this.ticksUntilFlap--;
            }
        }

        this.prevWingRotation = this.wingRotation;
        this.prevDestPos = this.destPos;

        this.destPos += 0.2D;
        this.destPos = minMax(0.01F, 1.0F, this.destPos);

        if (this.isOnGround()) {
            this.destPos = 0.0F;
        }

        this.wingRotation += 1.233F;
    }

    public static float minMax(float min, float max, float value) {
        return Math.min(max, Math.max(min, value));
    }

    @Override
    public void onMountedJump(float par1, float par2) {
        if (this.getRemainingJumps() > 0 && this.motionY < 0.0D) {
            if (!this.isOnGround()) {
                this.motionY = 0.7D;
                this.worldObj.playSoundAtEntity(this, "mob.bat.takeoff", 0.15F, MathHelper.clamp_float(this.rand.nextFloat(), 0.7f, 1.0f) + MathHelper.clamp_float(this.rand.nextFloat(), 0f, 0.3f));

                if (!this.worldObj.isRemote) {
                    this.setRemainingJumps(this.getRemainingJumps() - 1);
                }

                this.spawnExplosionParticle();
            } else {
                this.motionY = 0.89D;
            }
        }
    }

    @Override
    public float getMountedMoveSpeed() {
        return this.getMoaType().getMoaProperties().getMoaSpeed();
    }

    public void setToAdult() {
        this.setGrowingAge(0);
    }

    @Override
    public boolean interact(EntityPlayer player) {
        ItemStack stack = player.getCurrentEquippedItem();

        if (stack != null && this.isPlayerGrown() && !this.worldObj.isRemote) {
            Item currentItem = stack.getItem();

            if (this.isChild() && this.isHungry()) {
                if (this.getAmountFed() < 3 && currentItem == ItemsAether.aechor_petal) {
                    if (!player.capabilities.isCreativeMode) {
                        --stack.stackSize;
                    }

                    this.increaseAmountFed(1);

                    if (this.getAmountFed() >= 3) {
                        this.setToAdult();
                    } else {
                        this.resetHunger();
                    }
                }
            }

            if (currentItem == ItemsAether.nature_staff) {
                stack.damageItem(2, player);

                this.setSitting(this.isSitting() ? false : true);

                return true;
            }
        }

        return super.interact(player);
    }

    @Override
    public boolean canSaddle() {
        return !this.isChild() && this.isPlayerGrown();
    }

    @Override
    public void writeEntityToNBT(NBTTagCompound nbt) {
        super.writeEntityToNBT(nbt);

        nbt.setBoolean("playerGrown", this.isPlayerGrown());
        nbt.setInteger("remainingJumps", this.getRemainingJumps());
        nbt.setInteger("moaTypeId", this.getMoaTypeId());
        nbt.setByte("amountFed", this.getAmountFed());
        nbt.setBoolean("isHungry", this.isHungry());
        nbt.setBoolean("isSitting", this.isSitting());
    }

    @Override
    public void readEntityFromNBT(NBTTagCompound nbt) {
        super.readEntityFromNBT(nbt);

        this.setPlayerGrown(nbt.getBoolean("playerGrown"));
        this.setRemainingJumps(nbt.getInteger("remainingJumps"));
        this.setMoaType(AetherAPI.instance().getMoaType(nbt.getInteger("moaTypeId")));
        this.setAmountFed(nbt.getByte("amountFed"));
        this.setHungry(nbt.getBoolean("isHungry"));
        this.setSitting(nbt.getBoolean("isSitting"));
    }

    @Override
    protected String getLivingSound() {
        return "aether_legacy:aemob.moa.say";
    }

    @Override
    protected String getHurtSound() {
        return "aether_legacy:aemob.moa.say";
    }

    @Override
    protected String getDeathSound() {
        return "aether_legacy:aemob.moa.say";
    }

    @Override
    protected void func_145780_a(int p_145780_1_, int p_145780_2_, int p_145780_3_, Block p_145780_4_) {
        this.playSound("mob.pig.step", 0.15F, 1.0F);
    }

    @Override
    protected void dropFewItems(boolean recentlyHit, int lootLevel) {
        super.dropFewItems(recentlyHit, lootLevel);

        this.dropItem(Items.feather, 3);
    }

    public void fall() {
        int x = MathHelper.floor_double(this.posX);
        int y = MathHelper.floor_double(this.posY);
        int z = MathHelper.floor_double(this.posZ);
        boolean blockBeneath = !this.worldObj.isAirBlock(x, y - 1, z);

        if (this.motionY < 0.0D && !this.isRiderSneaking()) {
            this.motionY *= 0.6D;
        }

        if (blockBeneath) {
            this.setRemainingJumps(this.getMaxJumps());
        }
    }

    @Override
    public void jump() {
        if (!this.isSitting() && this.riddenByEntity == null) {
            super.jump();
        }
    }

    @Override
    public double getMountedYOffset() {
        return 1.25D;
    }

    @Override
    public EntityAgeable createChild(EntityAgeable matingAnimal) {
        return new EntityMoa(this.worldObj, this.getMoaType());
    }

}