#pragma once
#include <glad/glad.h>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>

// 3 axis lines: X=red, Y=green, Z=blue
// Each line: 2 vertices, each vertex has pos(3) + color(3)
static const float AXIS_VERTICES[] = {
	// X axis - red
	0.0f,
	0.0f,
	0.0f,
	1.0f,
	0.2f,
	0.2f,
	1.0f,
	0.0f,
	0.0f,
	1.0f,
	0.2f,
	0.2f,
	// Y axis - green
	0.0f,
	0.0f,
	0.0f,
	0.2f,
	1.0f,
	0.2f,
	0.0f,
	1.0f,
	0.0f,
	0.2f,
	1.0f,
	0.2f,
	// Z axis - blue
	0.0f,
	0.0f,
	0.0f,
	0.2f,
	0.4f,
	1.0f,
	0.0f,
	0.0f,
	1.0f,
	0.2f,
	0.4f,
	1.0f,
};

struct AxisRenderer {
	unsigned int VAO, VBO;
	unsigned int shader;
};

static const char *AXIS_VERT_SRC = R"(
#version 330 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aColor;
out vec3 vColor;
uniform mat4 uMVP;
void main() {
    vColor = aColor;
    gl_Position = uMVP * vec4(aPos, 1.0);
}
)";

static const char *AXIS_FRAG_SRC = R"(
#version 330 core
in vec3 vColor;
out vec4 FragColor;
void main() {
    FragColor = vec4(vColor, 1.0);
}
)";

inline AxisRenderer axis_init() {
	AxisRenderer r;

	// Compile inline shaders
	int success;
	char log[512];

	unsigned int vert = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vert, 1, &AXIS_VERT_SRC, NULL);
	glCompileShader(vert);
	glGetShaderiv(vert, GL_COMPILE_STATUS, &success);
	if (!success) {
		glGetShaderInfoLog(vert, 512, NULL, log);
		fprintf(stderr, "Axis vert: %s\n", log);
	}

	unsigned int frag = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(frag, 1, &AXIS_FRAG_SRC, NULL);
	glCompileShader(frag);
	glGetShaderiv(frag, GL_COMPILE_STATUS, &success);
	if (!success) {
		glGetShaderInfoLog(frag, 512, NULL, log);
		fprintf(stderr, "Axis frag: %s\n", log);
	}

	r.shader = glCreateProgram();
	glAttachShader(r.shader, vert);
	glAttachShader(r.shader, frag);
	glLinkProgram(r.shader);
	glDeleteShader(vert);
	glDeleteShader(frag);

	glGenVertexArrays(1, &r.VAO);
	glGenBuffers(1, &r.VBO);

	glBindVertexArray(r.VAO);
	glBindBuffer(GL_ARRAY_BUFFER, r.VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(AXIS_VERTICES), AXIS_VERTICES, GL_STATIC_DRAW);

	// pos
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)0);
	glEnableVertexAttribArray(0);
	// color
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)(3 * sizeof(float)));
	glEnableVertexAttribArray(1);

	glBindVertexArray(0);
	return r;
}

inline void axis_draw(const AxisRenderer &r, const glm::mat4 &mvp) {
	glUseProgram(r.shader);
	glUniformMatrix4fv(glGetUniformLocation(r.shader, "uMVP"), 1, GL_FALSE, glm::value_ptr(mvp));
	glBindVertexArray(r.VAO);
	glLineWidth(2.0f);
	glDrawArrays(GL_LINES, 0, 6);
	glBindVertexArray(0);
}

inline void axis_destroy(AxisRenderer &r) {
	glDeleteVertexArrays(1, &r.VAO);
	glDeleteBuffers(1, &r.VBO);
	glDeleteProgram(r.shader);
}
