pub struct Requirement<F, A> {
	checked: bool,
	current: bool,
	func: F,
	initial: bool,
	_arg: std::marker::PhantomData<A>,
}

impl<
	V,
	F: Fn(&V) -> bool,
> Requirement<F, V> {
	pub fn new(
		func: F,
		init: &V,
	) -> Self {
		let initial = func(init);
		Requirement {
			checked: false,
			current: initial,
			func,
			initial,
			_arg: std::marker::PhantomData,
		}
	}

	pub fn is_ok(&self) -> bool {
		self.current
	}

	pub fn is_relevant(&self, v: &Option<V>) -> bool {
		!self.checked
		&& v.as_ref().is_some_and(|v| (self.func)(v) != self.current)
	}

	pub fn mark_checked_if(&mut self, v: &Option<V>) {
		if v.is_some() {
			self.checked = true;
		}
	}

	pub fn apply(&mut self, v: &Option<V>) {
		if self.checked { return }
		let Some(v) = v else { return };
		self.checked = true;
		self.current = (self.func)(v);
	}

	pub fn reset(&mut self) {
		self.checked = false;
		self.current = self.initial;
	}
}

impl<F, A> std::fmt::Debug for Requirement<F, A> {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		f.debug_struct("Requirement")
			.field("initial", &self.initial)
			.field("checked", &self.checked)
			.field("current", &self.current)
			.finish()
	}
}
