use frienderer::{DrawCommand, Quad, RawImage, Renderer};
use glam::{Vec2, ivec2, uvec2, vec2};
use glfw::{Action, Context, Key, OpenGlProfileHint, WindowHint};
use image::ImageFormat;
use tracing::Level;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};

const OPENGL_PNG: &[u8] = include_bytes!("./opengl.png");

fn main() {
	let filter = tracing_subscriber::filter::Targets::new()
		.with_target("winit", Level::WARN)
		.with_default(Level::DEBUG);

	tracing_subscriber::registry()
		.with(tracing_subscriber::fmt::layer())
		.with(filter)
		.init();

	let mut glfw = glfw::init(glfw::fail_on_errors).unwrap();
	glfw.window_hint(WindowHint::ContextVersion(3, 3));
	glfw.window_hint(WindowHint::OpenGlProfile(OpenGlProfileHint::Core));
	glfw.window_hint(WindowHint::Resizable(true));
	glfw.window_hint(WindowHint::TransparentFramebuffer(true));

	let (mut window, events) = glfw
		.create_window(800, 600, "Images", glfw::WindowMode::Windowed)
		.expect("Failed to create GLFW window.");

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

	let (width, height) = window.get_size();
	let scale_factor = window.get_content_scale().0;
	let viewport = ivec2(width, height).as_vec2();

	let mut renderer = Renderer::new_with_str_loader(viewport, scale_factor, true, |symbol| {
		(window.get_proc_address(symbol))
			.map(|f| f as *const _)
			.unwrap_or_default()
	});
	renderer.set_clear_color(0.0, 0.0, 0.0, 0.5);

	let opengl_image = image::load_from_memory_with_format(OPENGL_PNG, ImageFormat::Png).unwrap();
	let opengl_texture = renderer.upload_texture(RawImage {
		width: opengl_image.width(),
		height: opengl_image.height(),
		pixels: opengl_image.as_bytes(),
	});
	let opengl_image_size = uvec2(opengl_image.width(), opengl_image.height()).as_vec2();

	while !window.should_close() {
		glfw.poll_events();
		for (_, event) in glfw::flush_messages(&events) {
			#[allow(clippy::single_match)]
			match event {
				glfw::WindowEvent::Key(Key::Escape, _, Action::Press, _) => window.set_should_close(true),
				_ => {}
			}
		}

		let (width, height) = window.get_size();

		renderer.resize(
			((width as f32) * scale_factor) as i32,
			((height as f32) * scale_factor) as i32,
			scale_factor,
		);

		{
			let start_pos = Vec2::splat(50.0);
			let pad = 50.0;

			let mut offset_x = 50.0;
			for i in 0..=4 {
				let subsize = opengl_image_size / (2_f32.powi(i));
				renderer.push_draw_command(DrawCommand::TextureQuad(
					Quad {
						pos: start_pos + vec2(offset_x, start_pos.y),
						size: subsize,
						origin: Vec2::ZERO,
						uv_pos: Vec2::ZERO,
						uv_size: Vec2::ONE,
						rotation: 0.0,
					},
					opengl_texture,
				));
				offset_x += subsize.x + pad;
			}
		}
		renderer.draw();

		window.swap_buffers();
	}
}
