#include <pch.hpp>

#include <orthographic_camera_controller.hpp>
#include <events/application_event.hpp>
#include <orthographic_camera.hpp>
#include <input/input_system.hpp>
#include <events/mouse_event.hpp>
#include <input/keycodes.hpp>
#include <events/event.hpp>
#include <core/time.hpp>

#include <glm/fwd.hpp>

namespace OpenEngine {
    OrthographicCameraController::OrthographicCameraController(float ratio, float zoom = 1.0f)
        : aspect_ratio(ratio), zoom(zoom),
        camera(-aspect_ratio * zoom, aspect_ratio * zoom, -zoom, zoom)
    {
    }

    void OrthographicCameraController::Translate(const glm::vec3& vector)
    {
        OE_PROFILE_FUNCTION();

        float velocity = translation_speed * Time::DeltaTime();
        camera_position += vector * velocity;
    }

    void OrthographicCameraController::Rotate(float speed)
    {
        OE_PROFILE_FUNCTION();

        float multiple = rotation_speed * Time::DeltaTime();
        camera_rotation += speed * multiple;
    }

    void OrthographicCameraController::OnUpdate()
    {
        OE_PROFILE_FUNCTION();

        if (Input::IsKeyPressed(OE_KEY_W))
            Translate({0, -1, 0});
        if (Input::IsKeyPressed(OE_KEY_A))
            Translate({1, 0, 0});
        if (Input::IsKeyPressed(OE_KEY_S))
            Translate({0, 1, 0});
        if (Input::IsKeyPressed(OE_KEY_D))
            Translate({-1, 0, 0});

        if (rotation) {
            if (Input::IsKeyPressed(OE_KEY_Q))
                Rotate(10);
            if (Input::IsKeyPressed(OE_KEY_E))
                Rotate(-10);

            camera.SetRotation(camera_rotation);
        }

        camera.SetPosition(camera_position);
    }

    void OrthographicCameraController::OnEvent(Event& e)
    {
        OE_PROFILE_FUNCTION();

        EventDispatcher dispatcher(e);
        dispatcher.Dispatch<MouseScrolledEvent>(BIND_EVENT_FN(OrthographicCameraController::OnMouseScrolled));
        dispatcher.Dispatch<WindowResizeEvent>(BIND_EVENT_FN(OrthographicCameraController::OnWindowResized));
    }

    void OrthographicCameraController::OnResize(float width, float height)
    {
        aspect_ratio = width / height;
        camera.SetProjection(-aspect_ratio * zoom, aspect_ratio * zoom, -zoom, zoom);
    }

    bool OrthographicCameraController::OnMouseScrolled(MouseScrolledEvent& e)
    {
        OE_PROFILE_FUNCTION();

        zoom -= e.GetYOffset() * 0.25f;
		zoom = std::max(zoom, 0.25f);
		camera.SetProjection(-aspect_ratio * zoom, aspect_ratio * zoom, -zoom, zoom);

        return false;
    }
    bool OrthographicCameraController::OnWindowResized(WindowResizeEvent& e)
    {
        OE_PROFILE_FUNCTION();

        OnResize(e.GetWidth(), e.GetHeight());

        return false;
    }
}
