use bevy_ecs::component::Component;
use std::fmt::{Display, Formatter};

#[derive(Component, Copy, Clone, Debug, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Horizontal {
	Left,
	#[default]
	Right,
}

impl From<Horizontal> for Directionality {
	fn from(value: Horizontal) -> Self {
		match value {
			Horizontal::Left => Directionality::Left,
			Horizontal::Right => Directionality::Right,
		}
	}
}

impl From<f32> for Horizontal {
	fn from(other: f32) -> Self {
		if other < 0.0 {
			Self::Left
		} else {
			Self::Right
		}
	}
}

impl Display for Horizontal {
	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
		match self {
			Horizontal::Left => f.write_str("left"),
			Horizontal::Right => f.write_str("right"),
		}
	}
}

#[derive(Component, Copy, Clone, Debug, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Vertical {
	Up,
	#[default]
	Down,
}

impl From<Vertical> for Directionality {
	fn from(value: Vertical) -> Self {
		match value {
			Vertical::Up => Directionality::Up,
			Vertical::Down => Directionality::Down,
		}
	}
}

impl From<f32> for Vertical {
	fn from(other: f32) -> Self {
		if other < 0.0 {
			Self::Up
		} else {
			Self::Down
		}
	}
}

impl Display for Vertical {
	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
		match self {
			Vertical::Up => f.write_str("up"),
			Vertical::Down => f.write_str("down"),
		}
	}
}

#[derive(Component, Copy, Clone, Debug, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Directionality {
	Up,
	Down,
	Left,
	Right,
	RightUp,
	LeftUp,
	LeftDown,
	#[default]
	RightDown,
}

impl Directionality {
	pub fn with_horizontal(&mut self, horizontal: Horizontal) {
		*self = match self {
			Self::Up | Self::Down | Self::Left | Self::Right => horizontal.into(),
			Self::RightUp | Self::LeftUp => match horizontal {
				Horizontal::Right => Self::RightUp,
				Horizontal::Left => Self::LeftUp,
			},
			Self::LeftDown | Self::RightDown => match horizontal {
				Horizontal::Right => Self::RightDown,
				Horizontal::Left => Self::LeftDown,
			},
		}
	}
	pub fn with_vertical(&mut self, vertical: Vertical) {
		*self = match self {
			Self::Up | Self::Down | Self::Left | Self::Right => vertical.into(),
			Self::RightUp | Self::RightDown => match vertical {
				Vertical::Up => Self::RightUp,
				Vertical::Down => Self::RightDown,
			},
			Self::LeftDown | Self::LeftUp => match vertical {
				Vertical::Up => Self::LeftUp,
				Vertical::Down => Self::LeftDown,
			},
		}
	}
}

impl Display for Directionality {
	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
		write!(
			f,
			"{}",
			match self {
				Self::Up => "up",
				Self::Down => "down",
				Self::Left => "left",
				Self::Right => "right",
				Self::RightUp => "right_up",
				Self::LeftUp => "left_up",
				Self::RightDown => "right_down",
				Self::LeftDown => "left_down",
			}
		)
	}
}
