// Copyright Marcus Del Favero 2025
// Licensed under the GNU AGPLv3 with an exception, see `README.md` for details
use glam::{Vec2, Vec3, Vec4};

mod private { // Using sealed traits: https://predr.ag/blog/definitive-guide-to-sealed-traits-in-rust/
	use super::*;

	pub trait Vector: Copy + Default {
		fn length_squared(self) -> f32;
		fn normalise(self) -> Self;
	}

	impl Vector for Vec2 { fn length_squared(self) -> f32 { self.length_squared() } fn normalise(self) -> Self { self.normalize() } }
	impl Vector for Vec3 { fn length_squared(self) -> f32 { self.length_squared() } fn normalise(self) -> Self { self.normalize() } }
	impl Vector for Vec4 { fn length_squared(self) -> f32 { self.length_squared() } fn normalise(self) -> Self { self.normalize() } }
}

pub trait Fix: private::Vector { // See clippy.toml for why this is needed
	fn is_normalised(self) -> bool {
		(self.length_squared() - 1.0).abs() < 1e-6 // Threshold which works for most sane (not very small and not very large) values
	}

	fn try_normalise(self) -> Option<Self> {
		let ret = self.normalise();
		ret.is_normalised().then_some(ret)
	}

	fn normalise_or(self, fallback: Self) -> Self { self.try_normalise().unwrap_or(fallback) }
	fn normalise_or_zero(self) -> Self { self.try_normalise().unwrap_or_default() }
}

impl<T> Fix for T where T: private::Vector {}
