package ru.dbotthepony.mc.otm.menu.input

import ru.dbotthepony.mc.otm.core.GetterSetter
import ru.dbotthepony.mc.otm.core.util.EnumValueCodec
import ru.dbotthepony.mc.otm.menu.MatteryMenu
import kotlin.reflect.KMutableProperty0

inline fun <reified E : Enum<E>> EnumInputWithFeedback(menu: MatteryMenu, allowedValues: Set<E>? = null) = EnumInputWithFeedback(menu, E::class.java, allowedValues = allowedValues)
inline fun <reified E : Enum<E>> EnumInputWithFeedback(menu: MatteryMenu, state: KMutableProperty0<E>?, allowedValues: Set<E>? = null) = EnumInputWithFeedback(menu, E::class.java, state, allowedValues = allowedValues)
inline fun <reified E : Enum<E>> EnumInputWithFeedback(menu: MatteryMenu, state: GetterSetter<E>?, allowedValues: Set<E>? = null) = EnumInputWithFeedback(menu, E::class.java, state, allowedValues = allowedValues)

inline fun <reified E : Enum<E>> EnumInputWithFeedback(menu: MatteryMenu, allowSpectators: Boolean, allowedValues: Set<E>? = null) = EnumInputWithFeedback(menu, E::class.java, allowSpectators, allowedValues = allowedValues)
inline fun <reified E : Enum<E>> EnumInputWithFeedback(menu: MatteryMenu, allowSpectators: Boolean, state: KMutableProperty0<E>?, allowedValues: Set<E>? = null) = EnumInputWithFeedback(menu, E::class.java, allowSpectators, state, allowedValues = allowedValues)
inline fun <reified E : Enum<E>> EnumInputWithFeedback(menu: MatteryMenu, allowSpectators: Boolean, state: GetterSetter<E>?, allowedValues: Set<E>? = null) = EnumInputWithFeedback(menu, E::class.java, allowSpectators, state, allowedValues = allowedValues)

class EnumInputWithFeedback<E : Enum<E>>(menu: MatteryMenu, clazz: Class<E>, allowSpectators: Boolean = false, val allowedValues: Set<E>? = null) : AbstractPlayerInputWithFeedback<E>() {
	val codec = EnumValueCodec(clazz)
	private val default = codec.values.first()

	override val input = menu.PlayerInput(codec, allowSpectators) { if (allowedValues == null || it in allowedValues) consumer?.invoke(it) }
	override val field = menu.mSynchronizer.ComputedField(getter = { supplier?.invoke() ?: default }, codec)

	constructor(menu: MatteryMenu, clazz: Class<E>, state: KMutableProperty0<E>?, allowedValues: Set<E>? = null) : this(menu, clazz, allowedValues = allowedValues) {
		if (state != null) {
			with(state)
		}
	}

	constructor(menu: MatteryMenu, clazz: Class<E>, state: GetterSetter<E>?, allowedValues: Set<E>? = null) : this(menu, clazz, allowedValues = allowedValues) {
		if (state != null) {
			with(state)
		}
	}

	constructor(menu: MatteryMenu, clazz: Class<E>, allowSpectators: Boolean, state: KMutableProperty0<E>?, allowedValues: Set<E>? = null) : this(menu, clazz, allowSpectators, allowedValues = allowedValues) {
		if (state != null) {
			with(state)
		}
	}

	constructor(menu: MatteryMenu, clazz: Class<E>, allowSpectators: Boolean, state: GetterSetter<E>?, allowedValues: Set<E>? = null) : this(menu, clazz, allowSpectators, allowedValues = allowedValues) {
		if (state != null) {
			with(state)
		}
	}
}
