/******************************************************************************
*	File		-	renderer2D.h
*	Author		-	Joey Pollack
*	Date		-	2022/07/13 (y/m/d)
*	Mod Date	-	2022/07/13 (y/m/d)
*	Description	-	The main 2D render class
******************************************************************************/

#ifndef LUNARIUM_RENDERER_2D_H_
#define LUNARIUM_RENDERER_2D_H_

#include <core/common_defs.h>
#include "render_common.h"
#include <utils/op_res.h>

#include <glm/glm.hpp>
#include <vector>

namespace lunarium
{
    class OrthographicCamera;


    class Renderer2D
    {
    public:
        struct FrameStats
        {
            int NumTris = 0;
            int DrawCalls = 0;
        };

        Texture* GetDebugTexture();
        void SetClearColor(Color color);
        Color GetClearColor();

        void ResetFrameStats();
        FrameStats GetFrameStats() const;
        void BeginDraw(OrthographicCamera* pCamera);
        void EndDraw();

        // Draw methods
        void DrawQuad(Rectangle quad, Color color, Texture* texture = nullptr, float angle = 0.0f);
        void DrawQuads(Rectangle* quads, u32 num_quads, Color* pColors);
        void DrawSprite(Texture& image, glm::vec2 position, Color color = {1.0f, 1.0f, 1.0f, 1.0f}, float angle = 0);
        void DrawSprite(Texture& image, Rectangle source, Rectangle destination, Color color = {1.0f, 1.0f, 1.0f, 1.0f}, float angle = 0);
        void DrawString(const char* string, Rectangle boundingArea, Color color = {1.0f, 1.0f, 1.0f, 1.0f}, float scale = 1.0f, int font = 0);

    private:
        friend class RenderContext;
        OpRes Initialize();
        void Shutdown();
        void Flush();

    private:
        Renderer2D();
        Renderer2D(const Renderer2D&) = delete;
        Renderer2D(const Renderer2D&&) = delete;
        Renderer2D operator=(const Renderer2D&) = delete;

    private: // data

        struct QuadData
        {
            int mNumQuads = 0;
            const int MaxQuads = 10000;
            const int MaxVertices = MaxQuads * 4;
            const int MaxIndices = MaxQuads * 6;
            const int TextureSlots = 32;

            // const glm::vec4 vert_pos[4] = {
            //         { -0.5f, 0.5f, 0.0f, 1.0f },    // TOP LEFT
            //         { 0.5f, 0.5f, 0.0f, 1.0f },     // TOP RIGHT
            //         {  0.5f, -0.5f, 0.0f, 1.0f },   // BOTTOM RIGHT
            //         { -0.5f, -0.5f, 0.0f, 1.0f }    // BOTTOM LEFT
            // };

            const glm::vec4 vert_pos[4] = {
                    { -0.5f, -0.5f, 0.0f, 1.0f }, 
                    {  0.5f, -0.5f, 0.0f, 1.0f }, 
                    {  0.5f,  0.5f, 0.0f, 1.0f },
                    { -0.5f,  0.5f, 0.0f, 1.0f } 
            };

            const glm::vec2 vert_tex[4] = {
                { 0.0f, 1.0f },
                { 1.0f, 1.0f },
                { 1.0f, 0.0f },
                { 0.0f, 0.0f },
            };

            struct Vertex
            {
                glm::vec3 pos;
                glm::vec2 tex_coord;
                glm::vec4 color;
                float tex_slot;
                glm::vec3 translation;
                float angle;
                glm::vec3 scale;
            };

            //const u32 indices[6] = { 0, 1, 2, 0, 2, 3 };
            const u32 indices[6] = { 0, 1, 2, 2, 3, 0 };

            Vertex* mRawVertexBuffer;
            int mRawBufferIndex;

            BufferLayout mBufferLayout;
            VertexBuffer* mVertexBuffer;
            //IndexBuffer* mIndexBuffer;
            Shader* mQuadShader;
        } mQuadData;

        FrameStats mFrameStats;
        OrthographicCamera* mpCamera;
        std::vector<Texture*> mLoadedTextures;
        Texture* mpWhiteTexture;
        Color mClearColor;

        /// DEBUG STUFF
        u32 mTVAO;
        u32 mTVBO;
    };
}


#endif  // LUNARIUM_RENDERER_2D_H_