#ifndef CAM_CONTROL_INCLUDED
#define CAM_CONTROL_INCLUDED

#include <controls/control.hpp>
#include <osi/mouse.hpp>
#include <osi/window.hpp>
#include <utils/math.hpp>

#include <utility>

class CameraController : public Controller
{
    glm::vec2 sens;
    float sens_multiplier = 10.0f;

    // Unsure if target should be a shared attribute for all camera types
    glm::vec3 target = glm::vec3(0.0f, 0.0f, 0.0f);

public:
    using Controller::Controller;

    void turn(float xoffset, float yoffset);

    glm::vec2 getSens() const { return sens; }
    void setSens(float x_size, float y_size);
    void setSensMultiplier(float _sens_multiplier) { sens_multiplier = _sens_multiplier; }

    glm::vec3 getTarget() const { return target; }
    void setTarget(node_ptr node) { target = node->getPositionWorld(); }
    void translateTarget(glm::vec3 direction) { target += direction; }

    std::pair<float, float> getMouseDelta(const osi::Mouse &mouse, 
                                          const osi::Window &window, 
                                          bool &editor_running);
    virtual void zoomCamera(const osi::Mouse &mouse) = 0;
    virtual void mouseMove(const osi::Mouse &mouse, const osi::Window &window, bool &editor_running) = 0;
};

class FreeFlyCameraController : public CameraController
{
public:
    using CameraController::CameraController;
    void forward() override;
    void backward() override;
    void left() override;
    void right() override;
    void up() override;
    void down() override;

    void zoomCamera(const osi::Mouse &mouse) { return; }
    
    void keyboardMove(const std::unordered_set<std::string> &held_keys, 
                      const std::unordered_set<std::string> &pressed_keys) override;
    void mouseMove(const osi::Mouse &mouse, const osi::Window &window, bool &editor_running) override;
};

class OrbitCameraController : public CameraController
{
    
    float zoom = 5.0f;

public:
    using CameraController::CameraController;

    glm::vec3 getUpVec() const override { return glm::vec3(0.0f, 1.0f, 0.0f); }

    void forward() override;
    void backward() override;
    void left() override;
    void right() override;
    void up() override;
    void down() override;

    void zoomCamera(const osi::Mouse &mouse) override;

    void keyboardMove(const std::unordered_set<std::string> &held_keys, 
                      const std::unordered_set<std::string> &pressed_keys) override;

    void mouseMove(const osi::Mouse &mouse, const osi::Window &window, bool &editor_running) override;
};

#endif