use std::convert::TryInto;

use glfw;
use glfw::{Action, Context, Key};
use gl;
use cgmath::{Matrix4, vec3, Point3, Deg, perspective};
use std::ffi::CStr;

const ScreenWidth: u32 = 480;
const ScreenHeight: u32 = 320;
const TITLE: &str = "GLFWtest";

mod shader;
mod model;
use model::Model;
mod camera;

fn main() {

    // initialize GLFW
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
    // set window hints
    glfw.window_hint(glfw::WindowHint::ContextVersion(3, 3));
    glfw.window_hint(glfw::WindowHint::OpenGlProfile(glfw::OpenGlProfileHint::Core));
    glfw.window_hint(glfw::WindowHint::OpenGlForwardCompat(false));
    glfw.window_hint(glfw::WindowHint::Resizable(false));
    glfw.window_hint(glfw::WindowHint::TransparentFramebuffer(true));
    glfw.window_hint(glfw::WindowHint::Decorated(false));


    //create window
    let (mut window, events) = glfw.create_window(ScreenWidth, ScreenHeight, TITLE, glfw::WindowMode::Windowed).unwrap();
    let (screen_width, screen_height) = window.get_framebuffer_size();

    // setup window
    window.make_current();
    window.set_key_polling(true);

    gl::load_with(|ptr| window.get_proc_address(ptr) as *const _);

    unsafe {
        gl::Viewport(0, 0, screen_width, screen_height);
        gl::ClearColor(1.0, 1.0, 1.0, 1.0);
        gl::Enable(gl::DEPTH_TEST);
    }


    // put biggie thingies here
    let model_Shader = shader::shader::new("model");
    let ourModel = Model::new("resources/models/backpack");
    let mut camera = camera::Camera {
        Position: cgmath::Point3::new(0.0, 0.0, 3.0),
        ..camera::Camera::default()
    };

    println!("entering main loop, time since init: {} seconds", glfw.get_time());
    // NOTE window loop
    while !window.should_close() {
           glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            glfw_handle_event(&mut window, event);
        }

        model_Shader.Use();


        // view/projection transformations
        let projection: Matrix4<f32> = perspective(Deg(camera.Zoom), ScreenWidth as f32 / ScreenHeight as f32, 0.1, 100.0);
        let view = camera.GetViewMatrix();
        model_Shader.setMat4(String::from("projection").as_str(), &projection);
        model_Shader.setMat4(String::from("view").as_str(), &view);


        let mut model = Matrix4::<f32>::from_translation(vec3(0.0, -1.75, 0.0));
        model = model * Matrix4::from_scale(0.2);
        model_Shader.setMat4(String::from("projection").as_str(), &model);
        ourModel.Draw(&model_Shader);

        unsafe {
            gl::Clear(gl::COLOR_BUFFER_BIT);
        };


        window.swap_buffers();
    }



}

pub fn clear_color(R: f32, G: f32, B: f32, A: f32) {
    unsafe { gl::ClearColor(R, G, B, A) }
}

fn glfw_handle_event(window: &mut glfw::Window, event: glfw::WindowEvent) {
    use glfw::WindowEvent as Event;
    use glfw::Key;
    use glfw::Action;

    match event {
        Event::Key(Key::Escape, _, Action::Press, _) => {
            window.set_should_close(true);
        },
        _ => {},
    }
}
