package de.craften.plugins.rpgplus.scripting.api.entities;

import de.craften.plugins.rpgplus.components.entitymanager.*;
import de.craften.plugins.rpgplus.components.entitymanager.traits.HorseTrait;
import de.craften.plugins.rpgplus.scripting.ScriptingModule;
import de.craften.plugins.rpgplus.scripting.api.entities.events.EntityEventManager;
import de.craften.plugins.rpgplus.scripting.util.ScriptUtil;
import de.craften.plugins.rpgplus.scripting.util.luaify.LuaFunction;
import de.craften.plugins.rpgplus.scripting.util.luaify.Luaify;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Horse;
import org.bukkit.entity.Rabbit;
import org.bukkit.entity.Villager;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;

import java.util.ArrayList;
import java.util.List;

/**
 * A lua module for entities.
 */
public class EntityModule extends LuaTable implements ScriptingModule {
    private final EntityEventManager entityEventManager;

    public EntityModule(EntityEventManager entityEventManager) {
        this.entityEventManager = entityEventManager;
        Luaify.convertInPlace(this);
    }

    @Override
    public LuaValue getModule() {
        return this;
    }

    @Override
    public void reset() {
        //nothing to reset
    }

    @LuaFunction("spawn")
    public EntityWrapper spawnEntity(LuaValue entityType, LuaValue optionsArg) {
        final EntityType type = EntityType.valueOf(entityType.checkjstring().toUpperCase());
        LuaTable options = optionsArg.checktable();

        RpgPlusEntity entity;
        if (type == EntityType.VILLAGER) {
            entity = new ManagedVillager(ScriptUtil.getLocation(optionsArg.checktable()));
        } else if (type == EntityType.HORSE) {
            entity = new ManagedHorse(ScriptUtil.getLocation(optionsArg.checktable()));
        } else if (type == EntityType.RABBIT) {
            entity = new ManagedRabbit(ScriptUtil.getLocation(optionsArg.checktable()));
        } else if (type == EntityType.OCELOT) {
            entity = new ManagedOcelot(ScriptUtil.getLocation(optionsArg.checktable()));
        } else {
            entity = new RpgPlusEntity(ScriptUtil.getLocation(optionsArg.checktable()), type);
        }

        entity.setName(ChatColor.translateAlternateColorCodes('&', options.get("name").optjstring("")));
        entity.setSecondName(ChatColor.translateAlternateColorCodes('&', options.get("secondName").optjstring("")));
        entity.setTakingDamage(!options.get("invulnerable").optboolean(false));
        entity.setNameVisible(options.get("nameVisible").optboolean(true));

        // TODO add corresponding traits to the entities
        /*
        switch (options.get("movementType").optjstring("local")) {
            case "normal":
                entity.setFrozen(false);
                break;
            case "frozen":
            case "local": //TODO entity should move the head when the movementType is set to local
                entity.setFrozen(true);
                break;
        }
        */

        if (entity instanceof ManagedVillager) {
            ManagedVillager villager = (ManagedVillager) entity;
            if (!options.get("profession").isnil()) {
                villager.setProfession(ScriptUtil.enumValue(options.get("profession"), Villager.Profession.class));
            }
        } else if (entity instanceof ManagedHorse) {
            HorseTrait horse = entity.getNpc().getTrait(HorseTrait.class);
            if (!options.get("style").isnil()) {
                horse.setStyle(ScriptUtil.enumValue(options.get("style"), Horse.Style.class));
            }
            if (!options.get("variant").isnil()) {
                horse.setVariant(ScriptUtil.enumValue(options.get("variant"), Horse.Variant.class));
            }
            if (!options.get("color").isnil()) {
                horse.setColor(ScriptUtil.enumValue(options.get("color"), Horse.Color.class));
            }
            if (!options.get("jumpStrength").isnil()) {
                horse.setJumpStrength(options.get("jumpStrength").checkdouble());
            }
            if (!options.get("domestication").isnil()) {
                horse.setDomestication(options.get("domestication").checkint());
            }
            if (!options.get("maxDomestication").isnil()) {
                horse.setMaxDomestication(options.get("maxDomestication").checkint());
            }
        } else if (entity instanceof ManagedRabbit) {
            ManagedRabbit rabbit = (ManagedRabbit) entity;
            if (!options.get("type").isnil()) {
                rabbit.setType(ScriptUtil.enumValue(options.get("type"), Rabbit.Type.class));
            }
        }

        entity.spawn();
        return EntityWrapper.create(entity, entityEventManager);
    }

    @LuaFunction("getNearby")
    public LuaTable getNearbyEntities(LuaValue locationParam, LuaValue radius) {
        Location location = ScriptUtil.getLocation(locationParam);
        List<EntityWrapper> entities = new ArrayList<>();

        /*
        for (ManagedEntityBase entity : entityManager.getEntitiesNear(location, radius.checkdouble())) {
            if (entity instanceof RpgPlusEntity) {
                entities.add(EntityWrapper.create((RpgPlusEntity) entity, entityEventManager));
            }
        }
        */
        // TODO get nearby entities

        return ScriptUtil.tableOf(entities);
    }
}

@@ -189,24 +189,263 @@
 HorseTrait;%0A
+import de.craften.plugins.rpgplus.components.entitymanager.traits.OcelotTrait;%0Aimport de.craften.plugins.rpgplus.components.entitymanager.traits.RabbitTrait;%0Aimport de.craften.plugins.rpgplus.components.entitymanager.traits.VillagerTrait;%0A
 import de.cr
@@ -857,118 +857,9 @@
 ity.
-EntityType;%0Aimport org.bukkit.entity.Horse;%0Aimport org.bukkit.entity.Rabbit;%0Aimport org.bukkit.entity.Villager
+*
 ;%0Aim
@@ -3276,31 +3276,24 @@
         
-Managed
 Villager
  village
@@ -3284,16 +3284,21 @@
 Villager
+Trait
  village
@@ -3305,32 +3305,53 @@
 r = 
-(ManagedVillager) entity
+entity.getNpc().getTrait(VillagerTrait.class)
 ;%0A  
@@ -4673,29 +4673,27 @@
         
-Managed
 Rabbit
+Trait
  rabbit 
@@ -4698,30 +4698,51 @@
 t = 
-(ManagedRabbit) entity
+entity.getNpc().getTrait(RabbitTrait.class)
 ;%0A  
@@ -4813,16 +4813,22 @@
 bbit.set
+Rabbit
 Type(Scr
@@ -4902,32 +4902,323 @@
      %7D%0A        %7D
+ else if (entity instanceof ManagedOcelot) %7B%0A            OcelotTrait ocelot = entity.getNpc().getTrait(OcelotTrait.class);%0A            if (!options.get(%22type%22).isnil()) %7B%0A                ocelot.setCatType(ScriptUtil.enumValue(options.get(%22type%22), Ocelot.Type.class));%0A            %7D%0A        %7D
 %0A%0A        entity

Fix setting initial villager and rabbit properties. Fix initial ocelot type being ignored.