#ifndef CONTROL_INCLUDED
#define CONTROL_INCLUDED

#include <common/node.hpp>
#include <utils/math.hpp>

#include <string>
#include <unordered_set>

class Controller
{
protected:
    float speed = 2.5f;
    float step = 0;

    node_ptr bound_node;

public:
    Controller() = default;

    node_ptr getNode() { return bound_node; }
    void setNode(node_ptr node) { bound_node = node; }
    void setup(float dt, node_ptr node);

    virtual glm::vec3 getFrontVec() const { return -bound_node->getRotationAxisZWorld(); }
    virtual glm::vec3 getUpVec() const { return bound_node->getRotationAxisYWorld(); }
    // virtual void setUpVec();

    void setStep(float dt);
    float getSpeed() const { return speed; }
    void setSpeed(float _speed);

    void teleport(glm::vec3 new_position) { bound_node->setPosVec(new_position); }
    void setRotation(glm::vec3 rotation) { bound_node->setRotationQuat(rotation); }
    void setRotation(glm::quat rotation) { bound_node->setRotationQuat(rotation); }

    void setPos(glm::vec3 position) { bound_node->setPosVec(position); }
    void setPos(float x, float y, float z) { bound_node->setPosVec(glm::vec3(x, y, z)); }
    void setPosX(float coord) { bound_node->setPosVec(glm::vec3(coord, bound_node->getPositionWorld().y, bound_node->getPositionWorld().z)); }
    void setPosY(float coord) { bound_node->setPosVec(glm::vec3(bound_node->getPositionWorld().x, coord, bound_node->getPositionWorld().z)); }
    void setPosZ(float coord) { bound_node->setPosVec(glm::vec3(bound_node->getPositionWorld().x, bound_node->getPositionWorld().y, coord)); }

    void translate(glm::vec3 direction) { bound_node->translatePosVec(direction); }

    virtual void keyboardMove(const std::unordered_set<std::string> &held_keys, 
                              const std::unordered_set<std::string> &pressed_keys);
    virtual void forward() = 0;
    virtual void backward() = 0;
    virtual void left() = 0;
    virtual void right() = 0;
    virtual void up() = 0;
    virtual void down() = 0;

    virtual void rotate(glm::vec3 rotational_difference);
};

#endif