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

import net.minecraft.network.RegistryFriendlyByteBuf
import ru.dbotthepony.kommons.util.Delegate
import ru.dbotthepony.mc.otm.menu.MatteryMenu
import ru.dbotthepony.mc.otm.network.MatteryStreamCodec
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: Delegate<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: Delegate<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 = MatteryStreamCodec.Enum<RegistryFriendlyByteBuf, E>(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.computed(delegate = { 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: Delegate<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: Delegate<E>?, allowedValues: Set<E>? = null) : this(menu, clazz, allowSpectators, allowedValues = allowedValues) {
		if (state != null) {
			with(state)
		}
	}
}
