class_name Option extends RefCounted

static var Unit = Option.some(null)

static func some(value: Variant) -> Option:
	return Some.new(value)

static var none: Option.None = None.new()

static func from(value: Variant) -> Option:
	if typeof(value) == TYPE_NIL:
		return Option.none
	else: return Option.some(value)

static func collect_some(options: Array[Option], ignore_none: bool = false) -> Option:
	var result = []
	for option in options:
		if option.is_some():
			result.push_back(option.unwrap())
		elif not ignore_none:
			return Option.none
	return Option.some(result)

class Some extends Option:
	var value: Variant

	func _init(val: Variant) -> void:
		value = val

	func and_then(fn: Callable) -> Option:
		return fn.call(value)

	func and_other(other: Option) -> Option:
		return other

	func contains(target_value: Variant) -> bool:
		return value == target_value

	func filter(fn: Callable) -> Option:
		if fn.call(value): return self
		else: return Option.none

	func flatten() -> Option:
		if value is Option:
			return value.flatten()
		else: return Option.some(value)

	func map(fn: Callable) -> Option:
		return Option.some(fn.call(value))

	func ok_or(_err: Variant) -> Result:
		return Result.ok(value)

	func ok_or_else(fn: Callable) -> Result:
		return Result.ok(value)

	func or_other(option: Option) -> Option:
		return self

	func inspect(fn: Callable) -> Option:
		fn.call(value)
		return self

	func is_some() -> bool:
		return true

	func is_none() -> bool:
		return false

	func unwrap() -> Variant:
		return value

	func unwrap_or(_default_value: Variant) -> Variant:
		return value

	func unwrap_or_else(_fn: Callable) -> Variant:
		return value

	func xor_other(other: Option) -> Option:
		if other.is_none():
			return self
		else:
			return Option.none

class None extends Option:
	func and_then(_fn: Callable) -> Option:
		return self

	func and_other(other: Option) -> Option:
		return self

	func contains(value: Variant) -> bool:
		return false

	func filter(_f: Callable) -> Option:
		return self

	func flatten() -> Option:
		return self

	func map(_fn: Callable) -> Option:
		return self

	func ok_or(err: Variant) -> Result:
		return Result.err(err)

	func ok_or_else(fn: Callable) -> Result:
		return Result.err(fn.call())

	func or_other(option: Option) -> Option:
		return option

	func inspect(_fn: Callable) -> Option:
		return self

	func is_some() -> bool:
		return false

	func is_none() -> bool:
		return true

	func unwrap() -> Variant:
		assert(false, "Called unwrap() on a None value")
		return null

	func unwrap_or(default_value: Variant) -> Variant:
		return default_value

	func unwrap_or_else(fn: Callable) -> Variant:
		return fn.call()

	func xor_other(other: Option) -> Option:
		if other.is_some():
			return other
		else:
			return self
