// Copyright Marcus Del Favero 2025
// Licensed under the GNU AGPLv3 with an exception, see `README.md` for details
use glam::Vec2;
use egui::{Context, LayerId, Order, Id, FontId, Rounding, Color32};

use super::{Camera, super::world::PowerupRenderer};

use crate::world::{colour::Colour, player::PlayerStyle, powerup::{Powerup, RADIUS as POWERUP_RADIUS}};
use crate::utils::maths::Circle;

const FONT_SIZE: f32 = 12.0;

pub(super) const PX_OFF: Vec2 = Vec2::new(0.0, -FONT_SIZE * 1.5);

pub struct WorldLabel {
	pos: Vec2, // Logical pixels
	text: String,
	colour: Colour,
}

impl WorldLabel {
	pub fn new_player(pos: Vec2, style: PlayerStyle) -> Option<WorldLabel> {
		style.get_name().map(|name| WorldLabel { pos, text: process(name.get()), colour: style.get_colour() })
	}

	pub fn new_powerup(powerup: &Powerup, powerup_renderer: &PowerupRenderer, camera: &Camera, lwinsize: Vec2) -> WorldLabel {
		let pos = camera.world_to_pixel_coords_with_size(powerup.get_pos() + Vec2::new(0.0, POWERUP_RADIUS * 2.0), lwinsize) + PX_OFF;
		let typ = powerup.get_type();
		WorldLabel { pos, text: Into::<&'static str>::into(typ).to_owned(), colour: powerup_renderer.average_colour(typ) }
	}

	pub fn render(&self, ctx: &Context) {
		let painter = ctx.layer_painter(LayerId { order: Order::Background, id: Id::NULL });
		let colour = Colour::name_colour_normal(self.colour.name_colour_dark());

		let galley = painter.layout_no_wrap(self.text.clone(), FontId::proportional(FONT_SIZE), colour);

		// Renders a rectangle under it to make it easier to read
		let mut bg_rect = galley.rect;
		bg_rect.set_center(self.pos.to_array().into());
		painter.rect_filled(bg_rect.expand(3.0), Rounding::ZERO, Color32::from_black_alpha(0x7f));

		// Renders the text
		let size = galley.size();
		let text_pos = self.pos - Vec2::new(size.x / 2.0, size.y / 2.0);
		painter.galley(text_pos.to_array().into(), galley, colour);
	}
}

/**
 * Does two jobs.
 *
 * The first is truncating the names if they're too long to prevent them from
 * being too long and looking weird.
 *
 * The second is to remove any newlines in the edge case that a user adds a
 * newline (probably to try and break things).
 */
pub(super) fn process(name: &str) -> String {
	const MAX_LEN: usize = 20;

	let mut ret = String::with_capacity(name.len().min(MAX_LEN + 1)); // Works in most cases

	/*
	 * Limiting based on the number of characters, not bytes.
	 *
	 * This is important because the purpose of this function is to prevent the
	 * name from being too long to avoid it looking weird when being rendered.
	 *
	 * I'm not interested in the length in bytes, and using bytes would mean
	 * users who use names in other non-ASCII languages would be disadvantaged,
	 * having their name truncated earlier.
	 */
	let mut count = 0;
	for ch in name.chars() {
		if ch == '\n' { continue; }

		if count >= MAX_LEN {
			ret.push('…');
			break
		}

		ret.push(ch);
		count += 1;
	}

	ret
}
