#pragma once

#include <frostbite2D/graphics/types.h>
#include <frostbite2D/graphics/texture.h>
#include <frostbite2D/graphics/shader.h>
#include <frostbite2D/types/type_alias.h>

namespace frostbite2D {

struct BatchKey {
  uint32_t shaderID;
  uint32_t textureID;
  uint32_t blendMode;
  
  bool operator<(const BatchKey& other) const {
    if (shaderID != other.shaderID) return shaderID < other.shaderID;
    if (textureID != other.textureID) return textureID < other.textureID;
    return blendMode < other.blendMode;
  }
};

class Batch {
public:
  static constexpr int MAX_QUADS = 2048;
  static constexpr int MAX_VERTICES = MAX_QUADS * 4;
  static constexpr int MAX_INDICES = MAX_QUADS * 6;
  
  Batch();
  ~Batch();
  
  bool init();
  void shutdown();
  
  void begin();
  void end();
  
  void submitQuad(const Quad& quad, const Transform2D& transform,
                Ptr<Texture> texture, Shader* shader,
                BlendMode blendMode = BlendMode::Normal);
  
  void flush();
  void flushIfNeeded(const BatchKey& newKey, Shader* shader, Ptr<Texture> texture);
  uint32 drawCallCount() const { return drawCallCount_; }
  
 private:
  void setupMesh();
  void flushCurrentBatch();
  
  struct BatchData {
    std::vector<Vertex> vertices;
    std::vector<uint16> indices;
    BatchKey key;
    Shader* shader = nullptr;
    Ptr<Texture> texture;
  };
  
  uint32_t vao_ = 0;
  uint32_t vbo_ = 0;
  uint32_t ibo_ = 0;
  
  BatchData currentBatch_;
  std::vector<BatchData> batches_;
  
  bool begun_ = false;
  uint32 drawCallCount_ = 0;
};

}
