#pragma once

#define CAMERA typeid(Camera).name()

#include "interfaces/IShader.hpp"
#include "Matrix4x4.hpp"
#include "Vector2.hpp"
#include "Vector3.hpp"
#include "interfaces/IRenderTarget.hpp"
#include "elements/BehaviourScript.hpp"
#include "uuid.h"

namespace TSE
{
    enum ProjectionType
    {
        Orthographic = 1,
        Perspective = 2,
    };

    class ICameraHelper
    {
    public:
        inline virtual void OnRenderTargetChanged(float width, float height) {};
    };

    class Camera : public IResizeNotifiable, public BehaviourScript
    {
    private:
        float RenderScale = 32;
        IRenderTarget* rt = nullptr;
        ProjectionType projection = ProjectionType::Orthographic;
        Matrix4x4* projectionMatrix = nullptr;
        Matrix4x4 viewMatrix;
        
        float nearClippingPlane = 0;
        float farClippingPlane = 100;
        
        //perspective
        float fov = 60;
        
        Vector2 lastRtSize = {0, 0};
    
    public:
        std::vector<uuids::uuid> layersNotToRender;
        static ICameraHelper* helper;
        static Camera* mainCamera;

        // Getter
        float GetRenderScale() const;
        ProjectionType GetProjection() const;
        float GetNearClippingPlane() const;
        float GetFarClippingPlane() const;
        float GetFov() const;
        const Vector2& GetRenderTargetSize() const;

        // Setter
        Vector3 SceenPositionToGamePosition(Vector2 screenPos);
        void SetRenderScale(float v);
        void SetProjection(ProjectionType v);
        void SetNearClippingPlane(float v);
        void SetFarClippingPlane(float v);
        void SetFov(float v);

        Camera();
        ~Camera();
        void OnResize(float width, float height, IResizable* wnd) override;
        void SetRenderTarget(IRenderTarget* target);
        IRenderTarget* GetRenderTarget();

        void RecalculateProjMatrix();

        void OnUpdate() override;
        void Start() override;

        void PreDraw(IShader* shader);

        void PostDraw();

        void Bind();
        void Unbind();
        void UpdateRenderTarget();

        inline const char* GetName() override
        {
            return "Camera";
        }
    };
} // namespace TSE
