/*
 *  <Short Description>
 *  Copyright (C) 2023  Brett Terpstra
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#ifndef BLT_WITH_GRAPHICS_BATCH_2D_RENDERER_H
#define BLT_WITH_GRAPHICS_BATCH_2D_RENDERER_H

#include "blt/gfx/model.h"
#include "blt/gfx/shader.h"
#include "blt/gfx/renderer/resource_manager.h"
#include <blt/std/hashmap.h>
#include <blt/std/memory_util.h>
#include <blt/math/vectors.h>
#include <string_view>
#include <vector>

namespace blt::gfx
{
    struct rectangle_t
    {
        float x, y, width, height, rotation = 0;
        
        rectangle_t(float x, float y, float width, float height, float rotation): x(x), y(y), width(width), height(height), rotation(rotation)
        {}
        
        rectangle_t(float x, float y, float width, float height): x(x), y(y), width(width), height(height)
        {}
    };
    
    struct draw_state
    {
        // texture to use
        std::string texture_name;
        // color to use
        blt::vec4 color;
        // how much to blend the texture into the color? note blending is always additive!
        blt::vec4 blend;
    };
    
    class batch_renderer_2d
    {
        private:
            struct vec_hash
            {
                std::size_t operator()(const blt::vec4& key) const
                {
                    using namespace blt::mem;
                    return type_cast<std::int32_t>(key.x()) ^ type_cast<std::int32_t>(key.y()) ^ type_cast<std::int32_t>(key.y()) ^
                           type_cast<std::int32_t>(key.z());
                }
            };
        
        private:
            vertex_array* square_vao = nullptr;
            shader_t* shader = nullptr;
            resource_manager& resources;
            HASHMAP<std::string, HASHMAP<blt::vec4, HASHMAP<blt::vec4, std::vector<rectangle_t>, vec_hash>, vec_hash>> complex_rectangles;
            size_t draw_count_ = 0;
        public:
            explicit batch_renderer_2d(resource_manager& resources): resources(resources)
            {}
            
            void create();
            
            inline void drawRectangle(std::string_view texture, const rectangle_t& rectangle)
            {
                const static blt::vec4 empty {0,0,0,0};
                const static blt::vec4 full {1,1,1,1};
                complex_rectangles[texture][empty][full].push_back(rectangle);
            }
            
            inline void drawRectangle(const blt::vec4& color, const rectangle_t& rectangle)
            {
                const static blt::vec4 empty {0,0,0,0};
                complex_rectangles[""][color][empty].push_back(rectangle);
            }
            
            inline void drawRectangle(const draw_state& draw_info, const rectangle_t& rectangle)
            {
                complex_rectangles[draw_info.texture_name][draw_info.color][draw_info.blend].push_back(rectangle);
            }
            
            void render();
            
            void cleanup();
            
            [[nodiscard]] inline size_t draw_count(){
                return draw_count_;
            }
    };
    
}

#endif //BLT_WITH_GRAPHICS_BATCH_2D_RENDERER_H
