#pragma once

#include <vector>
#include <Collage/types/animation.h>
#include <Collage/types/model.h>
#include <J3ML/LinearAlgebra/Vector3.h>
#include <J3ML/LinearAlgebra/Vector2.h>
#include <J3ML/Geometry/OBB.h>
#include <glad/glad.h>

///Forward declaration of entity.
class Entity;

typedef Vector2 TextureCoordinate;
using J3ML::LinearAlgebra::Vector3;
using J3ML::LinearAlgebra::Vector2;
using J3ML::Geometry::OBB;

///A point which makes up a model in 3D space.
typedef Vector3 Vertex;
///Determines how your texture is wrapped around the model.

///Drawable type. Models are stored in these.
class VertexArray {
private:
    ///A performance cheat. Most of the other kinds of colliders can be made from the OBB.
    ///It's faster to create an OBB when loading and then apply the rotation of the entity at the time, then create the other collider you want.
    OBB cachedOBB;
public:
    ///A list of the models animations.
    std::vector<Animation> animations;
    ///A list of points in 3d space that make up the model.
    std::vector<Vertex> vertices;
    ///A list specifying how to connect the vertices together to make triangular faces.
    std::vector<unsigned int> indices;
    ///A list containing texture coordinates, how the texture is to be wrapped around the model.
    std::vector<TextureCoordinate> texCoords;
    ///Reference list.
    std::vector<Entity*> usedBy;
    ///Id OpenGL uses to keep track of where the vertices are in v-ram.
    GLuint vbo = 0;
    ///Id OpenGL uses to keep track of where the indices are in v-ram.
    GLuint ebo = 0;
    ///Id OpenGL uses to keep track of where the texture coordinates are in v-ram.
    GLuint tbo = 0;
    ///Loads a model of a given filename.
    void load(const std::string& filename);
    [[nodiscard]] OBB getCachedOBB(const Matrix3x3& rotation) const;
    ///Returns the OBB given the rotation of the entity.
    [[nodiscard]] OBB getCachedOBB(const Vector3& rotation) const;
    [[nodiscard]] OBB getCachedOBB(const EulerAngle& rotation) const;
    ///Renders the model in the way you'd expect.
    virtual void draw();
    ///Renders a wireframe of the model with no texture.
    void drawWireframe();
    ///Constructor, calls load.
    explicit VertexArray(Entity* entity, const std::string& filename, bool storeOnGeometryList);
    VertexArray() = default;
    ///Removes Vertex Array from geometry list and deletes it.
    void erase() const;
};
