import math

import GL/opengl
import SDL2/sdl

import NimblePiE/Math/Matrix4f
import NimblePiE/Render/Shader
import NimblePiE/Render/VertexArrayObject

# Globals

var window: sdl.Window
var glContext: sdl.GLContext

# Init SDL

proc initSDL: bool = 
  
  if sdl.init(sdl.InitVideo) != 0:
    echo sdl.getError()
    return false

  if sdl.glSetAttribute(sdl.GLContextMajorVersion, 3) != 0:
    echo sdl.getError()
  if sdl.glSetAttribute(sdl.GLContextMinorVersion, 2) != 0:
    echo sdl.getError()
  if sdl.glSetAttribute(sdl.GLContextProfileMask, sdl.GLContextProfileCore) != 0:
    echo sdl.getError()

  window = sdl.createWindow("NimblePiE", sdl.WindowposUndefined, sdl.WindowposUndefined, 600, 600, sdl.WindowOpengl or sdl.WindowResizable)

  if window == nil:
    echo sdl.getError()
    return false

  glContext = sdl.glCreateContext(window)

  if glContext == nil:
    echo sdl.getError()
    return false
    
  if sdl.glMakeCurrent(window, glContext) != 0:
    echo sdl.getError()
    return false
    
  return true
  


# Constants

var vertices: array[0..8, GLfloat] = [
  GLfloat -0.5, GLfloat -0.5, GLfloat 0,
  GLfloat 0.5, GLfloat -0.5, GLfloat 0,
  GLfloat 0, GLfloat 0.5, GLfloat 0
]

var indices: array[0..2, GLuint] = [
  GLuint 0,
  GLuint 1,
  GLuint 2
]

## Main

if not initSDL(): quit(-1)

if not glInit(): quit(-1)

let shader: ShaderProgram = createShaderProgram(
  "assets/shaders/vertexShader.glsl",
  "assets/shaders/fragmentShader.glsl"
  )

glUseProgram(shader.progID)

const numObj = 1;

var VAOs: array[numObj, VertexArrayObject]
var objmats: array[numObj, Matrix4f]

for i in 0..<numObj:
  VAOs[i].vertices.add(vertices)
  VAOs[i].indices.add(indices)
  VAOs[i].bindData()
  objmats[i] = Matrix4f.Identity.translate(sin(i.float32/numObj*2'f32*PI), cos(i.float32/numObj*2'f32*PI), 0)

var vaoID, bufferID, elementID: GLuint

glGenVertexArrays(1, unsafeAddr vaoID)
glGenBuffers(1, unsafeAddr bufferID)
glGenBuffers(1, unsafeAddr elementID)

glBindVertexArray(vaoID)

glBindBuffer(GL_ARRAY_BUFFER, bufferID)
glBufferData(GL_ARRAY_BUFFER, GLfloat.sizeof * vertices.len, unsafeAddr vertices, GL_STATIC_DRAW)

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementID)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, GLuint.sizeof * indices.len, unsafeAddr indices, GL_STATIC_DRAW)

glVertexAttribPointer(0, 3, EGL_FLOAT, false, GLfloat.sizeof * 3, nil)
glEnableVertexAttribArray(0)
  
glClearColor(0.0'f32, 0.4'f32, 1.0'f32, 1.0'f32)

var mat: Matrix4f = Matrix4f.Identity

var running = true
while running:
  var event: sdl.Event
  while sdl.pollEvent(addr(event)) != 0:
    case event.kind:
      of sdl.Quit:
          running = false
      of sdl.Keydown:
        case event.key.keysym.sym
          of sdl.KUp:
            mat = mat.scale(1.01'f32)
          of sdl.KDown:
            mat = mat.scale(1/1.01'f32)
          else:
            discard
      else:
        discard
  
  
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
  
  let transformID = glGetUniformLocation(shader.progID, "transform")
  
  for i, VAO in VAOs.mpairs:
    objmats[i] = objmats[i].rotateZd(0.03)
    var transform = mat * objmats[i]
    glUniformMatrix4fv(transformID, GLsizei 1, false, cast[ptr GLfloat](addr (transform)))
    render VAO
    
  glBindVertexArray(vaoID)
  #glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nil)
  
  sdl.glSwapWindow(window)
      
quit(0)