package ru.dbotthepony.mc.otm.storage

import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.core.math.Decimal
import java.util.IdentityHashMap

open class StorageStackType<T : IStorageStack>(
	val identity: Class<T>,
	open val empty: T,

	/**
	 * Speculated energy required per operation on stack with size of 1
	 */
	open val energyPerOperation: Decimal,
) {
	open fun energyPerOperation(stack: T): Decimal {
		return energyPerOperation * stack.count
	}

	open fun energyPerStorage(stack: T) = energyPerOperation(stack)
	open fun energyPerExtraction(stack: T) = energyPerOperation(stack)
	open fun energyForUpkeep(stack: T) = Decimal.ZERO
}

@Suppress("unchecked_cast")
object StorageRegistry {
	private val REGISTRY = IdentityHashMap<Class<*>, StorageStackType<*>>()

	@JvmStatic
	fun register(type: StorageStackType<*>): StorageStackType<*> {
		check(!REGISTRY.containsKey(type.identity)) { "Already have storage stack type for ${type.identity}" }
		REGISTRY[type.identity] = type
		return type
	}

	/**
	 * Refer to [StorageStackType] for explanation of flags.
	 */
	@JvmStatic
	fun <T : IStorageStack> register(
		identity: Class<T>,
		empty: T,
		energyPerOperation: Decimal
	): StorageStackType<T> {
		return register(StorageStackType(identity, empty, energyPerOperation)) as StorageStackType<T>
	}

	@JvmStatic
	fun <T : IStorageStack> get(identity: Class<T>): StorageStackType<T> {
		val get = REGISTRY[identity] ?: throw NoSuchElementException("Registry does not contain $identity")
		return get as StorageStackType<T>
	}

	@JvmStatic
	fun <T : IStorageStack> getOrNull(identity: Class<T>): StorageStackType<T>? {
		return REGISTRY[identity] as StorageStackType<T>?
	}
}

inline val ITEM_STORAGE: StorageStackType<ItemStackWrapper> get() = OverdriveThatMatters.INSTANCE.ITEM_STORAGE()
