use std::{collections::HashMap, fs::read_dir, path::PathBuf};

use raylib::prelude::*;

#[derive(Default)]
pub struct Textures {
	map: HashMap<String, Texture2D>,
}

impl Textures {
	pub fn load_dir(&mut self, folder: &str, rl: &mut RaylibHandle, thread: &RaylibThread) {
		for d in read_dir(folder).unwrap().flatten() {
			let path = d.path();
			if path.is_file() {
				let name = path.file_stem().unwrap().to_string_lossy();
				let texture = rl
					.load_texture(thread, &format!("{folder}/{name}.png"))
					.unwrap();
				self.map.insert(name.to_string(), texture);
			}
		}
	}

	pub fn get(&self, name: &str) -> &Texture2D {
		self.map
			.get(name)
			.unwrap_or_else(|| self.map.get("missing").unwrap())
	}
}

pub fn simple_button(d: &mut RaylibDrawHandle, x: i32, y: i32, width: i32, height: i32) -> bool {
	let mouse_pos = d.get_mouse_position();
	let bounds = Rectangle {
		x: x as f32,
		y: y as f32,
		width: width as f32,
		height: height as f32,
	};
	let mut pressed = false;
	let color = if bounds.check_collision_point_rec(mouse_pos) {
		if d.is_mouse_button_pressed(MouseButton::MOUSE_BUTTON_LEFT) {
			pressed = true;
		}
		Color::DARKCYAN
	} else {
		Color::GRAY
	};
	d.draw_rectangle(x, y, width, height, color);
	pressed
}

pub fn simple_option_button<T>(
	d: &mut RaylibDrawHandle,
	x: i32,
	y: i32,
	width: i32,
	height: i32,
	option: T,
	current: &mut T,
) -> bool
where
	T: PartialEq,
{
	let color = if &option == current {
		Color::DARKCYAN
	} else {
		Color::GRAY
	};
	let bounds = Rectangle {
		x: x as f32,
		y: y as f32,
		width: width as f32,
		height: height as f32,
	};
	let mouse_pos = d.get_mouse_position();
	let mut changed = false;
	if d.is_mouse_button_pressed(MouseButton::MOUSE_BUTTON_LEFT)
		&& bounds.check_collision_point_rec(mouse_pos)
		&& current != &option
	{
		*current = option;
		changed = true;
	}
	d.draw_rectangle_rec(bounds, color);
	changed
}

pub fn text_input(
	d: &mut RaylibDrawHandle,
	bounds: Rectangle,
	text: &mut String,
	is_selected: &mut bool,
) -> bool {
	let mut changed = false;
	let (bg, border) = if *is_selected {
		(Color::DARKCYAN, Color::CYAN)
	} else {
		(Color::GRAY, Color::DIMGRAY)
	};
	d.draw_rectangle_rec(bounds, border);
	d.draw_rectangle_rec(shrink_rec(bounds, 2.), bg);
	let drawn_text = if *is_selected {
		&format!("{text}_")
	} else {
		&text
	};
	d.draw_text(
		drawn_text,
		bounds.x as i32 + 4,
		bounds.y as i32 + 4,
		20,
		Color::WHITE,
	);
	let mouse_pos = d.get_mouse_position();
	if d.is_mouse_button_pressed(MouseButton::MOUSE_BUTTON_LEFT)
		&& (bounds.check_collision_point_rec(mouse_pos) || *is_selected)
	{
		*is_selected = !*is_selected;
	}

	if *is_selected {
		if d.is_key_pressed(KeyboardKey::KEY_ESCAPE) {
			*is_selected = false;
		}
		if d.is_key_pressed(KeyboardKey::KEY_BACKSPACE) && !text.is_empty() {
			changed = true;
			text.pop();
		}
		let char_code = unsafe { ffi::GetCharPressed() };
		let c = if char_code > 0 {
			char::from_u32(char_code as u32)
		} else {
			None
		};
		if let Some(c) = c {
			changed = true;
			text.push(c);
		}
	}
	changed
}

pub fn texture_option_button<T>(
	d: &mut RaylibDrawHandle,
	pos: Vector2,
	texture: &Texture2D,
	option: T,
	current: &mut T,
	tex_size: f32,
	border: f32,
	// tooltip
) where
	T: PartialEq,
{
	let color = if &option == current {
		Color::DARKCYAN
	} else {
		Color::GRAY
	};
	let bounds = Rectangle {
		x: pos.x,
		y: pos.y,
		width: tex_size + border * 2.,
		height: tex_size + border * 2.,
	};
	d.draw_rectangle_rec(bounds, color);
	d.draw_texture_ex(
		texture,
		pos + Vector2::new(border, border),
		0.,
		tex_size / texture.width as f32,
		Color::WHITE,
	);

	let mouse_pos = d.get_mouse_position();
	if d.is_mouse_button_pressed(MouseButton::MOUSE_BUTTON_LEFT)
		&& bounds.check_collision_point_rec(mouse_pos)
	{
		*current = option;
	}
}

pub fn shrink_rec(rec: Rectangle, a: f32) -> Rectangle {
	Rectangle {
		x: rec.x + a,
		y: rec.y + a,
		width: rec.width - a * 2.,
		height: rec.height - a * 2.,
	}
}

pub fn userdata_dir()->PathBuf{
	PathBuf::from("user")
}