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

import com.google.common.collect.Streams
import net.minecraft.core.BlockPos
import net.minecraft.world.item.BlockItem
import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.Item
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.state.BlockBehaviour
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.VoxelShape
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
import ru.dbotthepony.mc.otm.block.getShapeForEachState
import ru.dbotthepony.mc.otm.core.collect.SupplierMap
import ru.dbotthepony.mc.otm.core.get
import ru.dbotthepony.mc.otm.core.math.BlockRotationFreedom
import ru.dbotthepony.mc.otm.core.util.WriteOnce
import ru.dbotthepony.mc.otm.registry.MDeferredRegister
import ru.dbotthepony.mc.otm.registry.MRegistry
import ru.dbotthepony.mc.otm.shapes.BlockShape
import java.util.function.Supplier
import java.util.stream.Stream

/**
 * Base + Colored
 */
class DecorativeBlock<B : Block>(
	baseName: String,
	private val provider: (DyeColor?) -> B,
) : ColoredDecorativeBlock<B>(baseName, provider) {
	private var _block: Supplier<B> by WriteOnce()
	private var _item: Supplier<Item> by WriteOnce()

	val block: Block get() = _block.get()
	val item: Item get() = _item.get()

	val allBlocks: Map<DyeColor?, B> by lazy {
		check(registeredBlocks) { "Didn't register blocks yet" }
		SupplierMap(Streams.concat(MRegistry.DYE_ORDER.stream().map { it to blockMap[it]!! }, Stream.of(null to _block)))
	}

	val allItems: Map<DyeColor?, Item> by lazy {
		check(registeredItems) { "Didn't register items yet" }
		SupplierMap(Streams.concat(MRegistry.DYE_ORDER.stream().map { it to itemMap[it]!! }, Stream.of(null to _item)))
	}

	override fun registerBlocks(registry: MDeferredRegister<Block>) {
		_block = registry.register(baseName) { provider.invoke(null) }
		super.registerBlocks(registry)
	}

	override fun registerItems(registry: MDeferredRegister<Item>) {
		_item = registry.register(baseName) { BlockItem(_block.get(), Item.Properties().stacksTo(64)) }
		super.registerItems(registry)
	}

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

		fun rotatable(baseName: String, provider: (DyeColor?) -> BlockBehaviour.Properties): DecorativeBlock<Block> {
			return DecorativeBlock(baseName) {
				RotatableMatteryBlock(provider.invoke(it))
			}
		}

		fun rotatable(baseName: String, shape: BlockShape, rotationFreedom: BlockRotationFreedom, provider: (DyeColor?) -> BlockBehaviour.Properties): DecorativeBlock<RotatableMatteryBlock> {
			return DecorativeBlock(baseName) {
				object : RotatableMatteryBlock(provider.invoke(it)) {
					override fun rotationFreedom(): BlockRotationFreedom {
						return rotationFreedom
					}

					private val shapes = getShapeForEachState(rotationProperty) { shape.rotateFromNorth(it[rotationProperty]).computeShape() }

					override fun getShape(
						state: BlockState,
						blockGetter: BlockGetter,
						pos: BlockPos,
						context: CollisionContext
					): VoxelShape {
						return shapes[state]!!
					}
				}
			}
		}
	}
}
