using System.Drawing;
using OpenTK;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.Desktop;
using OpenTK.Graphics.OpenGL;

using OpenTK.Mathematics;
using Buffer = System.Buffer;


namespace OpenTKStuff;


public class Game : GameWindow
{

    private int vertexBufferHandle;
    private int shaderProgramHandle;
    private int vertexArrayHandle;
    private int indexBufferHandle;

    private float[] vertices;
    
    public Game() : base(
        GameWindowSettings.Default, 
        new NativeWindowSettings() { Title = "FunFunGame!", ClientSize = new Vector2i(1920, 1080), WindowState = WindowState.Fullscreen }
        ) { }

    protected override void OnResize(ResizeEventArgs e) {
        GL.Viewport(0, 0, e.Width, e.Height);
        base.OnResize(e);
    }

    protected override void OnLoad() {
        GL.ClearColor(Color4.Goldenrod);

        //we represent a square as two triangles ;( idk why; this is so cruel

        float size = 1080;
        
        //vec3 rgba4
        vertices = [
            -size, size, 0, 1, 1, 0, 0,
            -size, -size, 0, 1, 0, 0, 1,
            size, -size, 0, 0, 1, 0, 1,
            size, size, 0, 0, 0, 1, 1,
        ];

        int[] indices = [
            0, 1, 2,
            2, 3, 0
        ];
        
        //todo: error checking

        vertexBufferHandle = GL.GenBuffer();
        GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferHandle);
        GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * sizeof(float), vertices, BufferUsageHint.StaticDraw);
        
        //UNBINDS BUFFER, tells OpenGL to stop working on the buffer
        GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
        
        
        indexBufferHandle = GL.GenBuffer();
        GL.BindBuffer(BufferTarget.ElementArrayBuffer, indexBufferHandle);
        GL.BufferData(BufferTarget.ElementArrayBuffer, indices.Length * sizeof(int), indices, BufferUsageHint.StaticDraw);
        GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
        
        
        
        int vxShader = GL.CreateShader(ShaderType.VertexShader);
        GL.ShaderSource(vxShader, File.ReadAllText("/home/avery/Programming/OpenTKStuff/OpenTKStuff/vertex.glsl"));
        GL.CompileShader(vxShader);
        
        int fgShader = GL.CreateShader(ShaderType.FragmentShader);
        GL.ShaderSource(fgShader, File.ReadAllText("/home/avery/Programming/OpenTKStuff/OpenTKStuff/fragment.glsl"));
        GL.CompileShader(fgShader);
        
        shaderProgramHandle = GL.CreateProgram();
        GL.AttachShader(shaderProgramHandle, vxShader);
        GL.AttachShader(shaderProgramHandle, fgShader);
        
        GL.LinkProgram(shaderProgramHandle);

        GL.GetShaderInfoLog(vxShader, out string info);
        Console.WriteLine(info);
        
        GL.GetShaderInfoLog(fgShader, out string info1);
        Console.WriteLine(info1);
        
        
        
        //clear memory
        GL.DetachShader(shaderProgramHandle, vxShader);
        GL.DetachShader(shaderProgramHandle, fgShader);
        
        GL.DeleteShader(vxShader);
        GL.DeleteShader(fgShader);


        int[] viewport = new int[4];
        GL.GetInteger(GetPName.Viewport, viewport);
        
        GL.UseProgram(shaderProgramHandle);
        int viewPortSizeUniformHandle = GL.GetUniformLocation(shaderProgramHandle, "ViewPortSize");
        
        GL.Uniform2(viewPortSizeUniformHandle, (float) viewport[2], (float) viewport[3]);
        GL.UseProgram(0);
        
        
        
        //setup vertex array
        vertexArrayHandle = GL.GenVertexArray();
        GL.BindVertexArray(vertexArrayHandle);
        
        GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferHandle);
        //defines the position attribute! total vertex size is 7 floats, and position starts at 0
        GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 7 * sizeof(float), 0);
        //we advance 3 * sizeof(float) bytes to get to the color, which is 4 values long
        GL.VertexAttribPointer(1, 4, VertexAttribPointerType.Float, false, 7 * sizeof(float), 3 * sizeof(float));
        GL.EnableVertexAttribArray(0);
        GL.EnableVertexAttribArray(1);
        
        GL.BindVertexArray(0);
        
        

        base.OnLoad();
    }

    protected override void OnUnload() {
        
        //clear binding
        GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
        GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
        GL.UseProgram(0);
        GL.BindVertexArray(0);
        
        //delete everything
        GL.DeleteBuffer(indexBufferHandle);
        GL.DeleteBuffer(vertexBufferHandle);
        GL.DeleteProgram(shaderProgramHandle);
        GL.DeleteVertexArray(vertexArrayHandle);
        
        base.OnUnload();
    }

    protected override void OnUpdateFrame(FrameEventArgs args) {
        base.OnUpdateFrame(args);
    }

    protected override void OnRenderFrame(FrameEventArgs args) {
        
        GL.Clear(ClearBufferMask.ColorBufferBit);
        
        GL.UseProgram(shaderProgramHandle);
        GL.BindVertexArray(vertexArrayHandle);
        GL.BindBuffer(BufferTarget.ElementArrayBuffer, indexBufferHandle);
        GL.DrawElements(PrimitiveType.Triangles, 6, DrawElementsType.UnsignedInt, 0);
        
        //for (int i = 0; i < vertices.Length; i+=7) {
        //    vertices[i] += .00001f;
        //    vertices[i + 1] += .00001f;
        //    vertices[i + 2] += .00001f;
        //}
        //
        //GL.BindBuffer(BufferTarget.ArrayBuffer, vertexArrayHandle);
        //GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * sizeof(float), vertices, BufferUsageHint.StaticDraw);
        
                
        //Swap buffers
        SwapBuffers();
        base.OnRenderFrame(args);
    }
}