package thebetweenlands.common.entity.mobs;

import java.util.List;

import javax.annotation.Nullable;

import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityCreature;
import net.minecraft.entity.IEntityLivingData;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.datasync.DataParameter;
import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.SoundCategory;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import thebetweenlands.api.audio.IEntitySound;
import thebetweenlands.api.entity.IEntityBL;
import thebetweenlands.api.entity.IEntityMusic;
import thebetweenlands.client.audio.EntityMusicLayers;
import thebetweenlands.client.audio.GreeblingMusicSound;
import thebetweenlands.client.render.particle.BLParticles;
import thebetweenlands.client.render.particle.ParticleFactory;
import thebetweenlands.common.registries.SoundRegistry;
import thebetweenlands.common.sound.BLSoundEvent;

/**
 * Created by Josh on 8/19/2018.
 */
public class EntityGreebling extends EntityCreature implements IEntityBL, IEntityMusic {
	protected static final byte EVENT_START_DISAPPEARING = 40;
	protected static final byte EVENT_DISAPPEAR = 41;
	
	private static final DataParameter<Integer> TYPE = EntityDataManager.createKey(EntityGreebling.class, DataSerializers.VARINT);
	private static final DataParameter<EnumFacing> FACING = EntityDataManager.createKey(EntityGreebling.class, DataSerializers.FACING);

	public int disappearTimer = 0;

	public EntityGreebling(World worldIn) {
		super(worldIn);
		this.setSize(1, 0.75f);
	}

	private static final class GreeblingGroup implements IEntityLivingData {
		public boolean hasType1;
		public boolean hasType2;
		public int count;
	}

	@Nullable
	@Override
	public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, @Nullable IEntityLivingData livingdata) {
		super.onInitialSpawn(difficulty, livingdata);

		if(livingdata == null) {
			livingdata = new GreeblingGroup();
		}

		if(livingdata instanceof GreeblingGroup) {
			GreeblingGroup group = (GreeblingGroup) livingdata;

			if(group.count > 0 && (!group.hasType1 || !group.hasType2)) {
				if(!group.hasType1) {
					this.setType(0);
				} else {
					this.setType(1);
				}
			} else {
				this.setType(rand.nextInt(2));
				if(this.getType() == 0) {
					group.hasType1 = true;
				} else {
					group.hasType2 = true;
				}
			}

			group.count++;
		} else {
			this.setType(rand.nextInt(2));
		}

		this.dataManager.set(FACING, EnumFacing.HORIZONTALS[rand.nextInt(EnumFacing.HORIZONTALS.length)]);

		return livingdata;
	}

	@Override
	protected void entityInit() {
		super.entityInit();
		this.dataManager.register(TYPE, 0);
		this.dataManager.register(FACING, EnumFacing.NORTH);
	}

	public void setType(int type) {
		this.dataManager.set(TYPE, type);
	}

	public int getType() {
		return this.dataManager.get(TYPE);
	}

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

		this.prevRotationPitch = this.rotationPitch = 0;
		this.prevRotationYaw = this.rotationYaw = this.dataManager.get(FACING).getHorizontalAngle();
		this.prevRenderYawOffset = this.renderYawOffset = this.dataManager.get(FACING).getHorizontalAngle();

		if (disappearTimer > 0 && disappearTimer < 8) disappearTimer++;
		
		if(!this.world.isRemote) {
			if (disappearTimer == 5) this.world.setEntityState(this, EVENT_DISAPPEAR);
			if (disappearTimer >= 8) setDead();
			
			List<EntityPlayer> nearPlayers = world.getEntitiesWithinAABB(EntityPlayer.class, getEntityBoundingBox().grow(4.5, 5, 4.5), e -> !e.capabilities.isCreativeMode && !e.isInvisible());
			if (disappearTimer == 0 && !nearPlayers.isEmpty()) {
				disappearTimer++;
				this.world.playSound(null, this.posX, this.posY, this.posZ, SoundRegistry.GREEBLING_VANISH, SoundCategory.NEUTRAL, 1, 1);
				this.world.setEntityState(this, EVENT_START_DISAPPEARING);
			}
		}
	}

	@SideOnly(Side.CLIENT)
	@Override
	public void handleStatusUpdate(byte id) {
		super.handleStatusUpdate(id);
		
		if(id == EVENT_START_DISAPPEARING) {
			disappearTimer = 1;
		} else if(id == EVENT_DISAPPEAR) {
			doLeafEffects();
		}
	}
	
	private void doLeafEffects() {
		if(world.isRemote) {
			int leafCount = 40;
			float x = (float) (posX);
			float y = (float) (posY + 1.3F);
			float z = (float) (posZ);
			while (leafCount-- > 0) {
				float dx = world.rand.nextFloat() * 1 - 0.5f;
				float dy = world.rand.nextFloat() * 1f - 0.1F;
				float dz = world.rand.nextFloat() * 1 - 0.5f;
				float mag = 0.08F + world.rand.nextFloat() * 0.07F;
				BLParticles.WEEDWOOD_LEAF.spawn(world, x, y, z, ParticleFactory.ParticleArgs.get().withMotion(dx * mag, dy * mag, dz * mag));
			}
		}
	}

	@Override
	public void writeEntityToNBT(NBTTagCompound compound) {
		super.writeEntityToNBT(compound);
		compound.setInteger("type", getType());
		compound.setInteger("facing", this.dataManager.get(FACING).getHorizontalIndex());
	}

	@Override
	public void readEntityFromNBT(NBTTagCompound compound) {
		super.readEntityFromNBT(compound);
		setType(compound.getInteger("type"));
		this.dataManager.set(FACING, EnumFacing.byHorizontalIndex(compound.getInteger("facing")));
	}

	@Override
	public void knockBack(Entity entityIn, float strength, double xRatio, double zRatio) { }

	@Override
	public boolean canBePushed() {
		return false;
	}

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

	@Override
	protected void collideWithNearbyEntities() { }

	@Override
	public void applyEntityCollision(Entity entityIn) { }

	@Override
	public BLSoundEvent getMusicFile(EntityPlayer listener) {
		return null;
	}

	@SideOnly(Side.CLIENT)
	@Override
	public IEntitySound getMusicSound(EntityPlayer listener) {
		return new GreeblingMusicSound(this.getType(), this, 0.75f);
	}

	@Override
	public double getMusicRange(EntityPlayer listener) {
		return 40.0D;
	}

	@Override
	public boolean isMusicActive(EntityPlayer listener) {
		return this.isEntityAlive();
	}

	@Override
	public int getMusicLayer(EntityPlayer listener) {
		return this.getType() == 0 ? EntityMusicLayers.GREEBLING_1 : EntityMusicLayers.GREEBLING_2;
	}

	@Override
	public boolean canInterruptOtherEntityMusic(EntityPlayer listener) {
		return false;
	}

	public void setFacing(EnumFacing facing) {
		this.dataManager.set(FACING, facing);
	}
}
