use std::path::Path;

use bmp::Pixel;
use font8x8::{UnicodeFonts, BASIC_FONTS};

use crate::{interval::Interval, vec3::Color};

fn linear_to_gamma(linear_component: f64) -> f64 {
	if linear_component > 0.0 {
		return linear_component.sqrt();
	}

	0.0
}

pub fn write_image<P: AsRef<Path>>(
	path: P,
	image: &[Color],
	width: u32,
	height: u32,
	logs: &str,
) -> std::io::Result<()> {
	let per_pixel = (logs.len() / (width as usize  * height as usize)).min(1);
	assert_ne!(per_pixel, 0);

	let mut out = bmp::Image::new(width * per_pixel as u32 * 8, height * per_pixel as u32 * 8);
	
	for y in 0..height {
		for x in 0..width {
			let index = (y as usize * width as usize) + x as usize;

			let r = linear_to_gamma(image[index as usize].r());
			let g = linear_to_gamma(image[index as usize].g());
			let b = linear_to_gamma(image[index as usize].b());

			const INTENSITY: Interval = Interval::new(0.000, 0.999);

			let r = (INTENSITY.clamp(r) * 256.0) as u8;
			let g = (INTENSITY.clamp(g) * 256.0) as u8;
			let b = (INTENSITY.clamp(b) * 256.0) as u8;

			for y_sub in 0..per_pixel {
				for x_sub in 0..per_pixel {
					let y_idx = (y as usize + y_sub) * width as usize;
					let x_idx = x as usize + x_sub;
					let letter = logs.chars().nth(y_idx + x_idx).unwrap();
					let letter_map = BASIC_FONTS.get(letter).unwrap();

					for (char_row_idx, char_row) in letter_map.into_iter().enumerate() {
						for bit in 0..8 {
							let color = match char_row & 1 << bit {
								0 => Pixel::new(0, 0, 0),
								_ => Pixel::new(r, g, b),
							};

							out.set_pixel((x_idx as u32 * 8) + bit as u32, ((y as u32 + y_sub as u32) * 8) + char_row_idx as u32, color);
						}
					}
				}
			}
		}
	}

	out.save(path)?;

	Ok(())
}
