// Copyright 2026 Gabriel Bjørnager Jensen.
//
// This file is part of LOOKLOOK.
//
// LOOKLOOK is free software: you can redistribute
// it and/or modify it under the terms of the GNU
// Affero General Public License as published by
// the Free Software Foundation, either version 3
// of the License, or (at your option) any later
// version.
//
// LOOKLOOK is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Af-
// fero General Public License along with LOOKLOOK.
// If not, see <https://www.gnu.org/licenses/>.

//! The [`ColourDepth`] type.

use std::cmp::Ordering;
use std::fmt::{self, Debug, Display, Formatter};
use std::mem::transmute;
use std::pat::pattern_type;

/// A colour depth.
#[repr(transparent)]
#[derive(Copy)]
#[derive_const(Clone)]
pub struct ColourDepth(pattern_type!(u8 is 1..=2));

impl ColourDepth {
	/// Constructs a new colour depth.
	///
	/// The provided value is measured in count of
	/// octets (bytes,) e.g. a value of `1` equates to
	/// `8` bits.
	///
	/// If the provided value is zero or greater than
	/// `2`,  this constructor will return [`None`].
	#[inline]
	#[must_use]
	pub const fn new(value: usize) -> Option<Self> {
		if value >= 1 && value <= 2 {
			let value = unsafe { Self::new_unchecked(value) };

			Some(value)
		} else {
			None
		}
	}

	/// Unsafely constructs a new colour depth.
	///
	/// # Safety
	///
	/// The provided value must be greater than or equal
	/// to `1` and less than or equal to `2`.
	#[inline(always)]
	#[must_use]
	#[track_caller]
	pub const unsafe fn new_unchecked(value: usize) -> Self {
		unsafe { transmute::<u8, Self>(value as u8) }
	}

	/// Retrieves the colour depth as [`u8`], meaasured
	/// in count of octets.
	#[inline(always)]
	#[must_use]
	pub const fn as_u8(self) -> u8 {
		unsafe { transmute::<Self, u8>(self) }
	}

	/// Retrieves the colour depth as [`usize`], meaasured
	/// in count of octets.
	#[inline]
	#[must_use]
	pub const fn as_usize(self) -> usize {
		self.as_u8().into()
	}
}

impl Debug for ColourDepth {
	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
		Debug::fmt(&self.as_u8(), f)
	}
}

const impl Default for ColourDepth {
	#[inline(always)]
	fn default() -> Self {
		const { Self::new(1).unwrap() }
	}
}

impl Display for ColourDepth {
	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
		Display::fmt(&self.as_u8(), f)?;
		f.write_str("b")?;

		Ok(())
	}
}

const impl Eq for ColourDepth {}

const impl Ord for ColourDepth {
	#[inline]
	fn cmp(&self, other: &Self) -> Ordering {
		self.as_u8().cmp(&other.as_u8())
	}
}

const impl PartialEq for ColourDepth {
	#[inline]
	fn eq(&self, other: &Self) -> bool {
		self.as_u8().eq(&other.as_u8())
	}
}

const impl PartialOrd for ColourDepth {
	#[inline]
	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
		self.as_u8().partial_cmp(&other.as_u8())
	}
}
