package projectzombie.entity;

import bdf.types.BdfNamedList;
import bdf.types.BdfObject;
import gl_engine.texture.TextureRef3D;
import gl_engine.vec.Vec2d;
import gl_engine.vec.Vec2i;
import gl_engine.vec.Vec3d;
import projectzombie.entity.particle.ParticleBlood;
import projectzombie.init.Resources;
import projectzombie.init.Sounds;
import projectzombie.tiles.Tile;
import projectzombie.tiles.TileBulletBreakable;
import projectzombie.util.math.random.RandomHelpers;
import projectzombie.world.chunk.Chunk;
import projectzombie.world.layer.Layer;

public class EntityBullet extends EntityParticle
{
	private static final TextureRef3D BULLET = Resources.ATLAS.get("/particle/bullet.png");
	
	private int time = 0;
	private Entity parent;
	
	private double damage;
	
	public EntityBullet(BdfObject bdf) {
		BdfClassLoad(bdf);
	}
	
	@Override
	public void BdfClassLoad(BdfObject bdf) {
		super.BdfClassLoad(bdf);
		
		BdfNamedList nl = bdf.getNamedList();
		time = nl.get("time").getInteger();
		damage = nl.get("damage").getDouble();
	}
	
	@Override
	public void BdfClassSave(BdfObject bdf) {
		super.BdfClassSave(bdf);
		
		BdfNamedList nl = bdf.getNamedList();
		nl.set("time", bdf.newObject().setInteger(time));
		nl.set("damage", bdf.newObject().setDouble(damage));
	}
	
	public EntityBullet(Vec3d pos, Vec3d velocity, Entity parent, double damage, int despawn_time) {
		super(pos, velocity);
		
		// Store some specified values
		this.parent = parent;
		this.damage = damage;
		this.time = despawn_time;
		this.hasGravity = false;
		
		// Play the gun sound
		Sounds.GUN.play(pos, 2);
	}
	
	@Override
	public void tick(Chunk chunk, Layer layer) {
		super.tick(chunk, layer);
		
		chunk = layer.getChunk(getPos().xz());
		
		// Is the bullets new position intersecting a solid object
		{
			// Get the position of the tile the bullet is over
			Vec2i tpos = getPos().xz().toInt();
			
			// Get the foreground tile and the background tile
			Tile tile_f = chunk.getFrontTile(tpos).tile;
			Tile tile_b = chunk.getBackTile(tpos).tile;
			
			// Is the tile solid and has the bullet crashed into it
			if(tile_f.tileSolid) {
				if(getPos().xz().squareDistance(new Vec2d(tpos.x + 0.5, tpos.y + 0.5)) < tile_f.tileHitbox)
				{
					// Break the block
					if(tile_f instanceof TileBulletBreakable && RandomHelpers.randrange(rand,
							((TileBulletBreakable)tile_f).getBulletBreakChance()) == 0) {
						chunk.breakFrontTile(tpos);
					}
					
					// Delete the bullet
					kill();
				}
			} if(tile_b.tileSolid) {
				if(getPos().xz().squareDistance(new Vec2d(tpos.x + 0.5, tpos.y + 0.5)) < tile_b.tileHitbox)
				{
					// Break the block
					if(tile_f instanceof TileBulletBreakable && RandomHelpers.randrange(rand,
							((TileBulletBreakable)tile_f).getBulletBreakChance()) == 0) {
						chunk.breakBackTile(tpos);
					}
					
					// Delete the bullet
					kill();
				}
			}
		}
		
		// Loop over the nearby entities
		for(Entity e : layer.getNearbyEntities(getPos().xz(), 1))
		{
			// Is this entity alive and not the parent
			if(e instanceof EntityAlive && e != parent && e.getPos().squareDistance(this.getPos()) < e.hitbox)
			{
				// Get the alive entity
				EntityAlive ea = (EntityAlive)e;
				
				// Spawn some blood particles
				chunk.spawnEntity(new ParticleBlood(getPos(), e.getVelocity().add(getVelocity()).divide(8)));
				
				// Knock the entity back abit
				e.push(getVelocity());
				
				Vec3d pos = getPos();
				
				// Play the hit noise
				Sounds.HIT.play(new Vec3d(pos.x, pos.y, pos.z), 1);
				
				// Harm the entity
				ea.addDamage(damage);
				
				// Kill the bullet
				chunk.killEntity(this);
				return;
			}
		}
		
		// Decrease time
		time -= 1;
		
		if(time <= 0) {
			chunk.killEntity(this);
		}
	}

	@Override
	public int getParticleCount() {
		return 1;
	}
	
	@Override
	public boolean shouldKillParticle() {
		return false;
	}

	@Override
	public EntityParticlePart getParticleAt(int id) {
		return new EntityParticlePart(BULLET, getPos(), 0.1, 0b1000);
	}
}
