package ru.dbotthepony.mc.otm.registry.objects

import net.minecraft.world.item.BlockItem
import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.Item
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.state.BlockBehaviour
import net.minecraftforge.registries.DeferredRegister
import net.minecraftforge.registries.RegistryObject
import ru.dbotthepony.mc.otm.core.collect.SupplierMap
import java.util.EnumMap

/**
 * Colored only
 */
@Suppress("PropertyName", "unused")
open class ColoredDecorativeBlock(
	val baseName: String,
	private val provider: (DyeColor) -> Block,
) {
	var registeredItems = false
		private set

	var registeredBlocks = false
		private set

	protected val itemMap = EnumMap<DyeColor, RegistryObject<Item>>(DyeColor::class.java)
	protected val blockMap = EnumMap<DyeColor, RegistryObject<Block>>(DyeColor::class.java)

	fun forEachItem(consumer: (String, DyeColor, Item) -> Unit) {
		consumer.invoke("black", DyeColor.BLACK, getItem(DyeColor.BLACK))
		consumer.invoke("blue", DyeColor.BLUE, getItem(DyeColor.BLUE))
		consumer.invoke("brown", DyeColor.BROWN, getItem(DyeColor.BROWN))
		consumer.invoke("cyan", DyeColor.CYAN, getItem(DyeColor.CYAN))
		consumer.invoke("gray", DyeColor.GRAY, getItem(DyeColor.GRAY))
		consumer.invoke("green", DyeColor.GREEN, getItem(DyeColor.GREEN))
		consumer.invoke("light_blue", DyeColor.LIGHT_BLUE, getItem(DyeColor.LIGHT_BLUE))
		consumer.invoke("light_gray", DyeColor.LIGHT_GRAY, getItem(DyeColor.LIGHT_GRAY))
		consumer.invoke("lime", DyeColor.LIME, getItem(DyeColor.LIME))
		consumer.invoke("magenta", DyeColor.MAGENTA, getItem(DyeColor.MAGENTA))
		consumer.invoke("orange", DyeColor.ORANGE, getItem(DyeColor.ORANGE))
		consumer.invoke("pink", DyeColor.PINK, getItem(DyeColor.PINK))
		consumer.invoke("purple", DyeColor.PURPLE, getItem(DyeColor.PURPLE))
		consumer.invoke("red", DyeColor.RED, getItem(DyeColor.RED))
		consumer.invoke("white", DyeColor.WHITE, getItem(DyeColor.WHITE))
		consumer.invoke("yellow", DyeColor.YELLOW, getItem(DyeColor.YELLOW))
	}

	fun forEachBlock(consumer: (String, DyeColor, Block) -> Unit) {
		consumer.invoke("black", DyeColor.BLACK, getBlock(DyeColor.BLACK))
		consumer.invoke("blue", DyeColor.BLUE, getBlock(DyeColor.BLUE))
		consumer.invoke("brown", DyeColor.BROWN, getBlock(DyeColor.BROWN))
		consumer.invoke("cyan", DyeColor.CYAN, getBlock(DyeColor.CYAN))
		consumer.invoke("gray", DyeColor.GRAY, getBlock(DyeColor.GRAY))
		consumer.invoke("green", DyeColor.GREEN, getBlock(DyeColor.GREEN))
		consumer.invoke("light_blue", DyeColor.LIGHT_BLUE, getBlock(DyeColor.LIGHT_BLUE))
		consumer.invoke("light_gray", DyeColor.LIGHT_GRAY, getBlock(DyeColor.LIGHT_GRAY))
		consumer.invoke("lime", DyeColor.LIME, getBlock(DyeColor.LIME))
		consumer.invoke("magenta", DyeColor.MAGENTA, getBlock(DyeColor.MAGENTA))
		consumer.invoke("orange", DyeColor.ORANGE, getBlock(DyeColor.ORANGE))
		consumer.invoke("pink", DyeColor.PINK, getBlock(DyeColor.PINK))
		consumer.invoke("purple", DyeColor.PURPLE, getBlock(DyeColor.PURPLE))
		consumer.invoke("red", DyeColor.RED, getBlock(DyeColor.RED))
		consumer.invoke("white", DyeColor.WHITE, getBlock(DyeColor.WHITE))
		consumer.invoke("yellow", DyeColor.YELLOW, getBlock(DyeColor.YELLOW))
	}

	fun getItem(dyeColor: DyeColor): Item {
		check(registeredItems) { "Didn't register items yet" }
		return itemMap[dyeColor]!!.get()
	}

	fun getBlock(dyeColor: DyeColor): Block {
		check(registeredBlocks) { "Didn't register items yet" }
		return blockMap[dyeColor]!!.get()
	}

	val blocks: Map<DyeColor, Block> by lazy {
		check(registeredBlocks) { "Didn't register blocks yet" }
		SupplierMap(blockMap.map { it.key to it.value::get })
	}

	val items: Map<DyeColor, Item> by lazy {
		check(registeredItems) { "Didn't register items yet" }
		SupplierMap(itemMap.map { it.key to it.value::get })
	}

	open fun registerBlocks(registry: DeferredRegister<Block>) {
		check(blockMap.isEmpty()) { "( ͡° ͜ʖ ͡°) No. \\(• ε •)/ ( ͠° ل͜ ͡°) ( ͠° ͟ ͟ʖ ͡°) (ง ͠° ͟ل͜ ͡°)ง ( ͡°︺͡°) ('ω')" }

		blockMap[DyeColor.WHITE] = registry.register("${baseName}_white") { provider.invoke(DyeColor.WHITE) }
		blockMap[DyeColor.ORANGE] = registry.register("${baseName}_orange") { provider.invoke(DyeColor.ORANGE) }
		blockMap[DyeColor.MAGENTA] = registry.register("${baseName}_magenta") { provider.invoke(DyeColor.MAGENTA) }
		blockMap[DyeColor.LIGHT_BLUE] = registry.register("${baseName}_light_blue") { provider.invoke(DyeColor.LIGHT_BLUE) }
		blockMap[DyeColor.YELLOW] = registry.register("${baseName}_yellow") { provider.invoke(DyeColor.YELLOW) }
		blockMap[DyeColor.LIME] = registry.register("${baseName}_lime") { provider.invoke(DyeColor.LIME) }
		blockMap[DyeColor.PINK] = registry.register("${baseName}_pink") { provider.invoke(DyeColor.PINK) }
		blockMap[DyeColor.GRAY] = registry.register("${baseName}_gray") { provider.invoke(DyeColor.GRAY) }
		blockMap[DyeColor.LIGHT_GRAY] = registry.register("${baseName}_light_gray") { provider.invoke(DyeColor.LIGHT_GRAY) }
		blockMap[DyeColor.CYAN] = registry.register("${baseName}_cyan") { provider.invoke(DyeColor.CYAN) }
		blockMap[DyeColor.PURPLE] = registry.register("${baseName}_purple") { provider.invoke(DyeColor.PURPLE) }
		blockMap[DyeColor.BLUE] = registry.register("${baseName}_blue") { provider.invoke(DyeColor.BLUE) }
		blockMap[DyeColor.BROWN] = registry.register("${baseName}_brown") { provider.invoke(DyeColor.BROWN) }
		blockMap[DyeColor.GREEN] = registry.register("${baseName}_green") { provider.invoke(DyeColor.GREEN) }
		blockMap[DyeColor.RED] = registry.register("${baseName}_red") { provider.invoke(DyeColor.RED) }
		blockMap[DyeColor.BLACK] = registry.register("${baseName}_black") { provider.invoke(DyeColor.BLACK) }

		registeredBlocks = true
	}

	private val properties = Item.Properties().stacksTo(64)

	open fun registerItems(registry: DeferredRegister<Item>) {
		check(itemMap.isEmpty()) { "( ͡° ͜ʖ ͡°) No. \\(• ε •)/ ( ͠° ل͜ ͡°) ( ͠° ͟ ͟ʖ ͡°) (ง ͠° ͟ل͜ ͡°)ง ( ͡°︺͡°) ('ω')" }
		check(registeredBlocks) { "wtffffff???????????" }

		itemMap[DyeColor.WHITE] = registry.register("${baseName}_white") { BlockItem(blockMap[DyeColor.WHITE]!!.get(), properties) }
		itemMap[DyeColor.ORANGE] = registry.register("${baseName}_orange") { BlockItem(blockMap[DyeColor.ORANGE]!!.get(), properties) }
		itemMap[DyeColor.MAGENTA] = registry.register("${baseName}_magenta") { BlockItem(blockMap[DyeColor.MAGENTA]!!.get(), properties) }
		itemMap[DyeColor.LIGHT_BLUE] = registry.register("${baseName}_light_blue") { BlockItem(blockMap[DyeColor.LIGHT_BLUE]!!.get(), properties) }
		itemMap[DyeColor.YELLOW] = registry.register("${baseName}_yellow") { BlockItem(blockMap[DyeColor.YELLOW]!!.get(), properties) }
		itemMap[DyeColor.LIME] = registry.register("${baseName}_lime") { BlockItem(blockMap[DyeColor.LIME]!!.get(), properties) }
		itemMap[DyeColor.PINK] = registry.register("${baseName}_pink") { BlockItem(blockMap[DyeColor.PINK]!!.get(), properties) }
		itemMap[DyeColor.GRAY] = registry.register("${baseName}_gray") { BlockItem(blockMap[DyeColor.GRAY]!!.get(), properties) }
		itemMap[DyeColor.LIGHT_GRAY] = registry.register("${baseName}_light_gray") { BlockItem(blockMap[DyeColor.LIGHT_GRAY]!!.get(), properties) }
		itemMap[DyeColor.CYAN] = registry.register("${baseName}_cyan") { BlockItem(blockMap[DyeColor.CYAN]!!.get(), properties) }
		itemMap[DyeColor.PURPLE] = registry.register("${baseName}_purple") { BlockItem(blockMap[DyeColor.PURPLE]!!.get(), properties) }
		itemMap[DyeColor.BLUE] = registry.register("${baseName}_blue") { BlockItem(blockMap[DyeColor.BLUE]!!.get(), properties) }
		itemMap[DyeColor.BROWN] = registry.register("${baseName}_brown") { BlockItem(blockMap[DyeColor.BROWN]!!.get(), properties) }
		itemMap[DyeColor.GREEN] = registry.register("${baseName}_green") { BlockItem(blockMap[DyeColor.GREEN]!!.get(), properties) }
		itemMap[DyeColor.RED] = registry.register("${baseName}_red") { BlockItem(blockMap[DyeColor.RED]!!.get(), properties) }
		itemMap[DyeColor.BLACK] = registry.register("${baseName}_black") { BlockItem(blockMap[DyeColor.BLACK]!!.get(), properties) }

		registeredItems = true
	}

	companion object {
		fun simple(baseName: String, provider: (DyeColor) -> BlockBehaviour.Properties): ColoredDecorativeBlock {
			return ColoredDecorativeBlock(baseName) {
				Block(provider.invoke(it))
			}
		}
	}
}
