#include "ItemEntity.h"

#include "Game.h"

#ifdef _WINDOWS
#    define __INT32_MAX__ 0x7FFFFFFF
#endif

ItemEntity::ItemEntity(
    Framework::Vec3<float> location, int dimensionId, int entityId)
    : Entity(EntityTypeEnum::ITEM, location, dimensionId, entityId)
{
    slot = new ItemSlot("Inventory", __INT32_MAX__, 0, 0, 0, ANY_DIRECTION, 0);
    addSlot(slot);
    faceOffset = {0.f, 0.f, 0.f};
    maxHP = 10;
    maxStamina = 10;
    maxHunger = 10;
    maxThirst = 10;
    setHP(10);
    setStamina(10);
    setHunger(10);
    setThirst(10);
    targetDistanceLimit = 4;
    maxMovementSpeed = 1;
}

void ItemEntity::prepareTick(const Dimension* zDimension)
{
    if (slot->zStack() == 0 && !removed) throw "Illegal State exception";
    if (movements.getEintragAnzahl() <= 1)
    {
        Entity* zOther = Game::INSTANCE->zNearestEntity(
            currentDimensionId, location, [this](Entity* zOther) {
                return zOther != this
                    && zOther->numberOfAddableItems(
                        slot->zStack(), NO_DIRECTION)
                    && (!this->slot->isFull()
                        || zOther->zType()->getId() != EntityTypeEnum::ITEM);
            });
        if (zOther)
        {
            MovementFrame frame;
            frame.direction = zOther->getPosition() - getPosition();
            frame.duration = 0.25;
            frame.movementFlags = 0x1; // TODO: torn on flight mode
            frame.targetPosition
                = getPosition() + frame.direction * (0.5f * maxMovementSpeed);
            addMovementFrame(frame);
        }
    }
    Entity::prepareTick(zDimension);
}

void ItemEntity::tick(const Dimension* zDimension)
{
    Entity* zOther = Game::INSTANCE->zNearestEntity(
        currentDimensionId, location, [this](Entity* zOther) {
            return zOther != this
                && zOther->numberOfAddableItems(slot->zStack(), NO_DIRECTION)
                && (!this->slot->isFull()
                    || zOther->zType()->getId() != EntityTypeEnum::ITEM);
        });
    if (zOther)
    {
        float d = location.abstand(zOther->getPosition());
        if (d < 0.5f)
        {
            // add items of this entity to the other entity
            zOther->interactWith(this, NO_DIRECTION)
                .pullItems(slot->getNumberOfItems(), 0);
            if (slot->getNumberOfItems() == 0) onDeath();
        }
    }
    Entity::tick(zDimension);
}

void ItemEntity::onFall(float collisionSpeed)
{
    if (collisionSpeed >= 50.f) this->setHP(0);
}

bool ItemEntity::hasDefaultModel() const
{
    return 0;
}

ModelInfo ItemEntity::getSpecialModel() const
{
    const ItemType* zItemType = 0;
    if (!slot->isEmpty()) zItemType = slot->zStack()->zItem()->zItemType();
    return !zItemType ? ModelInfo("", "", 0) : zItemType->getModel();
}

ItemEntityType::ItemEntityType()
    : EntityType(EntityTypeEnum::ITEM, ModelInfo("", "", 0))
{}

Entity* ItemEntityType::createEntity(
    Framework::Vec3<float> position, int dimensionId, int entityId) const
{
    return new ItemEntity(position, dimensionId, entityId);
}