#pragma once

#include <Critical.h>
#include <Either.h>
#include <Model3D.h>

#include "Area.h"
#include "EntityType.h"
#include "FactoryCraftModel.h"

class Block;

struct MovementFrame
{
    Framework::Vec3<float> direction;
    Framework::Vec3<float> targetPosition;
    int movementFlags = 0;
    double duration = 0;
};

enum MovementFlag
{
    MOVEMENT_FLAG_NONE = 0,
    MOVEMENT_FLAG_FORWARD = 0x1,
    MOVEMENT_FLAG_LEFT = 0x2,
    MOVEMENT_FLAG_BACKWARD = 0x4,
    MOVEMENT_FLAG_RIGHT = 0x8,
    MOVEMENT_FLAG_DOWN = 0x10,
    MOVEMENT_FLAG_UP = 0x20,
    MOVEMENT_FLAG_JUMP = 0x40,
    MOVEMENT_FLAG_FLY = 0x80,
};

class Entity : public FactoryCraftModel
{
private:
    int id;
    const EntityType* zType;
    Framework::Critical cs;
    bool playerControlled;
    float maxMovementSpeed;
    int lastFlags;
    double timeSinceSync;
    float gravityMultiplier;
    float jumpSpeed;
    Framework::Vec3<float> lastDirection;
    Framework::Array<MovementFrame> movements;
    Framework::Vec3<float> speed;
    MovementFrame currentFrame;

public:
    Entity(const EntityType* zType,
        Framework::Model3DData* model,
        Framework::Model3DTextur* texture,
        int id,
        Framework::Vec3<float> position,
        float maxMovementSpeed,
        float gravityMultiplier,
        float jumpSpeed,
        float size);
    ~Entity();

    void api(char* message);
    bool tick(double time) override;

    int getId() const;
    const EntityType* zEntityType() const;
    void lock();
    void unlock();
    void setPlayerControlled();
};