use std::rc::Rc;

use glam::{Vec2, vec2};
use glow::HasContext;

use crate::common::{create_shader_program, pop_debug_group, push_debug_group, slice_as_bytes};

const SRC_VERT_WHITE: &str = include_str!("./shaders/white.vert");
const SRC_FRAG_WHITE: &str = include_str!("./shaders/white.frag");

pub struct WhiteRectRenderer {
	gl: Rc<glow::Context>,
	shader: glow::Program,

	vao: glow::VertexArray,
	vbo: glow::Buffer,
}

impl WhiteRectRenderer {
	pub fn new(gl: Rc<glow::Context>) -> Self {
		unsafe {
			push_debug_group(&gl, "WhiteRectRenderer: init");

			let shader = create_shader_program(&gl, SRC_VERT_WHITE, SRC_FRAG_WHITE);

			let vao = gl.create_vertex_array().unwrap();
			gl.bind_vertex_array(Some(vao));

			let vbo = gl.create_buffer().unwrap();
			gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo));
			gl.buffer_data_u8_slice(glow::ARRAY_BUFFER, slice_as_bytes(SCREEN_VERTICES), glow::STATIC_DRAW);

			#[rustfmt::skip]
            {
                let a_position = gl.get_attrib_location(shader, "position").unwrap();
                gl.vertex_attrib_pointer_f32(a_position, 2, glow::FLOAT, false, size_of::<Vec2>() as i32, 0);
                gl.enable_vertex_attrib_array(a_position);
            };

			pop_debug_group(&gl);

			Self { gl, shader, vao, vbo }
		}
	}

	/// Returns the number of executed draw calls.
	pub fn draw(&self) -> usize {
		let gl = &self.gl;
		unsafe {
			push_debug_group(gl, "WhiteRectRenderer: draw");

			gl.bind_vertex_array(Some(self.vao));
			gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.vbo));
			gl.use_program(Some(self.shader));

			gl.draw_arrays(glow::TRIANGLES, 0, 6);

			pop_debug_group(gl);

			1
		}
	}
}

impl Drop for WhiteRectRenderer {
	fn drop(&mut self) {
		let gl = &self.gl;
		unsafe {
			push_debug_group(gl, "WhiteRectRenderer: drop");

			gl.delete_program(self.shader);
			gl.delete_vertex_array(self.vao);

			gl.delete_buffer(self.vbo);

			pop_debug_group(gl);
		}
	}
}

#[rustfmt::skip]
const SCREEN_VERTICES: &[Vec2] = &[
	vec2(-1.0, -1.0),
	vec2(-1.0,  1.0),
	vec2( 1.0,  1.0),
	vec2(-1.0, -1.0),
	vec2( 1.0,  1.0),
	vec2( 1.0, -1.0),
];
