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

import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.core.immutableMap
import ru.dbotthepony.mc.otm.core.math.RelativeSide
import ru.dbotthepony.mc.otm.menu.MatteryMenu

/**
 * [allowPull] and [allowPush] controls whenever player is allowed to change these options
 */
class ItemConfigPlayerInput(val menu: MatteryMenu, config: MatteryDeviceBlockEntity.ConfigurableItemHandler? = null, val allowPull: Boolean = false, val allowPush: Boolean = false) {
	private val allowedFlags = MatteryDeviceBlockEntity.ItemHandlerMode.values().map { menu.mSynchronizer.bool() to it }
	fun isAllowed(value: MatteryDeviceBlockEntity.ItemHandlerMode) = allowedFlags[value.ordinal].first.boolean

	inner class Piece(val side: RelativeSide) {
		fun isAllowed(value: MatteryDeviceBlockEntity.ItemHandlerMode) = this@ItemConfigPlayerInput.isAllowed(value)

		val pull = BooleanInputWithFeedback(menu)
		val push = BooleanInputWithFeedback(menu)
		val input = EnumInputWithFeedback<MatteryDeviceBlockEntity.ItemHandlerMode>(menu)

		var default by menu.mSynchronizer.enum(MatteryDeviceBlockEntity.ItemHandlerMode.DISABLED)

		init {
			pull.filter { allowPull && isAllowed(MatteryDeviceBlockEntity.ItemHandlerMode.INPUT) }
			push.filter { allowPush && isAllowed(MatteryDeviceBlockEntity.ItemHandlerMode.OUTPUT) }
		}

		fun with(config: MatteryDeviceBlockEntity.ConfigurableItemHandler.Piece) {
			pull.with(config::automatePull)
			push.with(config::automatePush)
			input.withSupplier { config.mode }.withConsumer { if (isAllowed(it)) config.mode = it }
		}
	}

	val pieces = immutableMap { for (side in RelativeSide.values()) put(side, Piece(side)) }

	fun with(config: MatteryDeviceBlockEntity.ConfigurableItemHandler) {
		for ((f, v) in allowedFlags) {
			f.boolean = v in config.possibleViews
		}

		for ((side, v) in config.pieces) {
			pieces[side]!!.with(v)
			pieces[side]!!.default = config.defaults[side]!!
		}
	}

	init {
		if (config != null) {
			with(config)
		}
	}
}
