#pragma once

#include "blitz/common/NonCopyable.h"

#include <vector>

namespace blitz {
namespace GL {

struct VertexAttribPointer {
	unsigned int m_Index;
	unsigned int m_Size;
	unsigned int m_Offset;
};

class ElementBuffer : private NonCopyable {
  private:
	unsigned int m_ID = 0;
	std::size_t m_TriangleCount;

  public:
	ElementBuffer(ElementBuffer&& other) {
		std::swap(m_ID, other.m_ID);
		m_TriangleCount = other.m_TriangleCount;
	}

	ElementBuffer(const std::vector<unsigned int>& indicies);
	~ElementBuffer();

	void Bind() const;
	void Unbind() const;

	std::size_t GetTriangleCount() const {
		return m_TriangleCount;
	}
};

class VertexBuffer : private NonCopyable {
  private:
	unsigned int m_ID = 0, m_DataStride;
	std::vector<VertexAttribPointer> m_VertexAttribs;

  public:
	VertexBuffer(VertexBuffer&& other) {
		std::swap(m_ID, other.m_ID);
		m_VertexAttribs = std::move(other.m_VertexAttribs);
		m_DataStride = other.m_DataStride;
	}

	VertexBuffer(const std::vector<float>& data, unsigned int stride);
	~VertexBuffer();

	void Bind() const;
	void Unbind() const;
	void AddVertexAttribPointer(unsigned int index, unsigned int coordinateSize, unsigned int offset);
	void BindVertexAttribs() const;
};

class VertexArray : private NonCopyable {
  private:
	unsigned int m_ID = 0;
	ElementBuffer m_ElementBuffer;
	std::vector<VertexBuffer> m_VertexBuffers;	// use to destroy vbos when become unused
  public:
	VertexArray(VertexArray&& other) : m_ElementBuffer(std::move(other.m_ElementBuffer)) {
		std::swap(m_ID, other.m_ID);
		m_VertexBuffers = std::move(other.m_VertexBuffers);
	}

	VertexArray(ElementBuffer&& indicies);
	~VertexArray();

	unsigned int GetVertexCount() const {
		return m_ElementBuffer.GetTriangleCount();
	}

	void BindVertexBuffer(VertexBuffer& vbo);
	void Bind() const;
	void Unbind() const;

  private:
	void BindElementArrayBuffer();
};

}  // namespace GL
}  // namespace blitz
