package electrosphere.entity.types.hitbox;

import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.types.attach.AttachUtils;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.entity.state.life.LifeState;
import electrosphere.entity.state.life.LifeUtils;
import electrosphere.game.server.effects.ParticleEffects;
import electrosphere.main.Globals;
import org.joml.Matrix4f;
import org.joml.Quaternionf;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector4f;

/**
 *
 * @author amaterasu
 */
public class HitboxUtils {
    
    
    public static Entity spawnRegularHitbox(Entity parent, String bone, float size){
        Entity rVal = new Entity();
        HitboxData data = new HitboxData();
        data.setActive(false);
        data.setBone(bone);
        data.setRadius(size);
        data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT);
        rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
        rVal.putData(EntityDataStrings.HITBOX_DATA, data);
        rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
        rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
        Globals.hitboxManager.registerHitbox(rVal);
        return rVal;
    }
    
    public static Entity spawnRegularHurtbox(Entity parent, String bone, float size){
        Entity rVal = new Entity();
        HitboxData data = new HitboxData();
        data.setActive(true);
        data.setBone(bone);
        data.setRadius(size);
        data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT);
        data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT);
        rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
        rVal.putData(EntityDataStrings.HITBOX_DATA, data);
        rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
        rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
        Globals.hitboxManager.registerHitbox(rVal);
        return rVal;
    }
    
    public static void updatePosition(Entity hitbox){
        Entity parent = ((Entity)hitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT));
        HitboxData hitboxData = getHitboxData(hitbox);
        String boneName = hitboxData.getBone();
        Quaternionf parentRotation = ((Quaternionf)EntityUtils.getRotation(parent));
        Vector3f positionScale = ((Vector3f)EntityUtils.getScale(parent));
        Vector3f worldPosition = new Vector3f();
        Vector3f bonePosition = EntityUtils.getActor(parent).getBonePosition(boneName);
        Vector3d parentPos = EntityUtils.getPosition(parent);
        worldPosition.set(bonePosition.x,bonePosition.y,bonePosition.z);
        Quaternionf rotation = new Quaternionf(parentRotation);
        
        worldPosition = worldPosition.mul(positionScale);

        worldPosition = worldPosition.rotate(rotation);
                
        
        worldPosition.add(new Vector3f((float)parentPos.x,(float)parentPos.y,(float)parentPos.z));
        
        ((Vector3d)hitbox.getData(EntityDataStrings.DATA_STRING_POSITION)).set(worldPosition);
    }
    
    public static void collideEntities(Entity generatorHitbox){
//        long generatorId = (Long)generatorHitbox.getData(EntityDataStrings.COLLISION_ENTITY_ID);

        //This is the entity the hitbox is attached to
        Entity generatorParent = (Entity)generatorHitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);
        
        for(Entity receiverHitbox : Globals.hitboxManager.getAllHitboxes()){
            
            Entity receiverParent = (Entity)receiverHitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);

            HitboxData generatorData = getHitboxData(generatorHitbox);
            HitboxData receiverData = getHitboxData(receiverHitbox);
            
            //if there is a collision
            //and the collision isn't against itself
            //and both hitboxes are active
            if(
                    receiverParent != generatorParent &&
                    Globals.collisionEngine.collisionSphereCheck(generatorHitbox, generatorData, receiverHitbox, receiverData) &&
                    generatorData.isActive() &&
                    receiverData.isActive()){
                //if two spheres collide, grab their hitbox types (eg hurt, hit, fire, etc)
                String generatorType = generatorData.getType();
                String receiverType = receiverData.getType();
                
                if(generatorType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT) && receiverType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT)){
                    damageHitboxColision(generatorHitbox, receiverHitbox);
                }
                
                if(generatorType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT) && receiverType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT)){
                    damageHitboxColision(receiverHitbox, generatorHitbox);
                }
            }
        }
    }
    
    public static void damageHitboxColision(Entity hitbox, Entity hurtbox){
        
        Entity hitboxParent = (Entity)hitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);
        Entity hurtboxParent = (Entity)hurtbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);
        
        //if the entity is attached to is an item, we need to compare with the parent of the item
        //to make sure you don't stab yourself for instance
        boolean isItem = hitboxParent.getDataKeys().contains(EntityDataStrings.ITEM_IS_ITEM);
        Entity hitboxAttachParent = AttachUtils.getParent(hitboxParent);
        
        if(isItem){
            if(hitboxAttachParent != hurtboxParent){
                LifeState lifeState = LifeUtils.getLifeState(hurtboxParent);
                int currentHp = lifeState.getLifeCurrent();
                LifeUtils.getLifeState(hurtboxParent).damage(20);
                if(currentHp > lifeState.getLifeCurrent()){
                    Vector3d hurtboxPos = EntityUtils.getPosition(hurtbox);
                    ParticleEffects.spawnSparks(new Vector3f((float)hurtboxPos.x,(float)hurtboxPos.y,(float)hurtboxPos.z).add(0,0.1f,0), 20, 40);
                }
                if(!LifeUtils.getLifeState(hurtboxParent).isIsAlive()){
                    EntityUtils.getPosition(hurtboxParent).set(Globals.spawnPoint);
                    LifeUtils.getLifeState(hurtboxParent).revive();
                }
            }
        } else {
            LifeUtils.getLifeState(hurtboxParent).damage(20);
            if(!LifeUtils.getLifeState(hurtboxParent).isIsAlive()){
                EntityUtils.getPosition(hurtboxParent).set(Globals.spawnPoint);
                LifeUtils.getLifeState(hurtboxParent).revive();
            }
        }
    }
    
    
    public static HitboxData getHitboxData(Entity e){
        return (HitboxData)e.getData(EntityDataStrings.HITBOX_DATA);
    }
    
}
