package ru.themixray.repeating_mod.render.buffer;

import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
import org.apache.commons.lang3.ArrayUtils;
import org.joml.Matrix4f;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import org.lwjgl.BufferUtils;
import ru.themixray.repeating_mod.render.shader.Shader;

import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;

import static org.lwjgl.opengl.GL33.*;

public class WorldBuffer {
    private final List<Vertex> vertices = new ArrayList<>();
    private final int drawMode;
    private final Shader shader;
    private FloatBuffer projectionMatrix;
    private final Vector3f cameraPos;
    private final Quaternionf cameraRot;

    public WorldBuffer(int drawMode, Shader shader, WorldRenderContext worldRenderContext) {
        this.drawMode = drawMode;
        this.shader = shader;
        this.cameraPos = worldRenderContext.camera().getPos().toVector3f();
        this.cameraRot = worldRenderContext.camera().getRotation().invert();
        this.projectionMatrix = worldRenderContext.projectionMatrix().mul(worldRenderContext.matrixStack().peek().getPositionMatrix()).get(BufferUtils.createFloatBuffer(16));
    }

    public void vert(Vector3f pos, float r, float g, float b, float a) {
        vertices.add(new Vertex(cameraRot.transform(pos.sub(cameraPos)), r, g, b, a));
    }

    public void draw() {
        BufferManager.bind();
        BufferManager.bindBuffer();

        BufferManager.writeBuffer(getBuffer());
        shader.uniformMatrix4f("u_projection", projectionMatrix);

        glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(1, 4, GL_FLOAT, false, 0, vertices.size() * 3 * 4L);
        glEnableVertexAttribArray(1);

        BufferManager.unbindBuffer();

        shader.bind();
        BufferManager.draw(drawMode, this.vertices.size());
        shader.unbind();

        BufferManager.unbind();
    }

    private FloatBuffer getBuffer() {
        FloatBuffer floatBuffer = BufferUtils.createFloatBuffer(vertices.size() * 7);
        ArrayList<Float> floats = new ArrayList<>();
        for (ru.themixray.repeating_mod.render.buffer.Vertex vertex : vertices) {
            floats.add(vertex.getPos().x);
            floats.add(vertex.getPos().y);
            floats.add(vertex.getPos().z);
        }
        for (ru.themixray.repeating_mod.render.buffer.Vertex vertex : vertices) {
            floats.add(vertex.getR());
            floats.add(vertex.getG());
            floats.add(vertex.getB());
            floats.add(vertex.getA());
        }
        Float[] floatArray = new Float[floats.size()];
        floats.toArray(floatArray);
        floatBuffer.put(ArrayUtils.toPrimitive(floatArray));
        return floatBuffer.flip();
    }
}
