/// Represents the value produced when a rule is matched. Will need to be inspected to find out
/// the raw data value. This value will typically correspond to an index in a spritesheet, but
/// there is no proscribed meaning - it will be application dependant and could represent some
/// other index or meaning
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(untagged))]
#[derive(Clone, Debug, Default)]
pub enum TileOutput {
	/// This output should be skipped. Noop equivalent
	#[default]
	Skip,
	/// This exact value should be produces
	Single(i32),
	/// Some method should be used to select one of the values in this list
	Random(Vec<i32>),
}

impl TileOutput {
	/// Create an output that can produce the input value when this output is selected
	pub const fn single(value: i32) -> Self {
		TileOutput::Single(value)
	}

	/// Create an output that can produce any of these input values when this output is selected
	pub const fn any(value: Vec<i32>) -> Self {
		TileOutput::Random(value)
	}

	/// Produce the value this output represents. Will use a default randomly seeded RNG to
	/// select from a list, if appropriate
	#[cfg(feature = "impl_fastrand")]
	pub fn resolve(&self) -> Option<i32> {
		self.resolve_with(&fastrand::Rng::default())
	}

	/// Produce the value this output represents. Will use a default randomly seeded RNG to
	/// select from a list, if appropriate
	#[cfg(feature = "impl_fastrand")]
	pub fn resolve_with(&self, rng: &fastrand::Rng) -> Option<i32> {
		match self {
			Self::Skip => None,
			Self::Single(val) => Some(*val),
			Self::Random(vals) => vals.get(rng.usize(0..vals.len())).copied(),
		}
	}
}
