package ru.dbotthepony.mc.otm.registry

import net.minecraft.client.renderer.blockentity.BlockEntityRenderers
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraftforge.eventbus.api.IEventBus
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent
import net.minecraftforge.registries.DeferredRegister
import net.minecraftforge.registries.ForgeRegistries
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.block.entity.*
import ru.dbotthepony.mc.otm.block.entity.tech.*
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleBlockEntity
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlockEntityExplosionDebugger
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlockEntitySphereDebugger
import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity
import ru.dbotthepony.mc.otm.block.entity.decorative.FluidTankBlockEntity
import ru.dbotthepony.mc.otm.block.entity.decorative.HoloSignBlockEntity
import ru.dbotthepony.mc.otm.block.entity.matter.*
import ru.dbotthepony.mc.otm.block.entity.storage.*
import ru.dbotthepony.mc.otm.block.entity.tech.AndroidStationBlockEntity
import ru.dbotthepony.mc.otm.block.entity.tech.BatteryBankBlockEntity
import ru.dbotthepony.mc.otm.block.entity.tech.EnergyServoBlockEntity
import ru.dbotthepony.mc.otm.block.entity.tech.GravitationStabilizerBlockEntity
import ru.dbotthepony.mc.otm.block.entity.tech.PlatePressBlockEntity
import ru.dbotthepony.mc.otm.client.render.blockentity.*

@Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS") // Type<*> is unused in BlockEntityType.Builder
object MBlockEntities {
	private val registry = DeferredRegister.create(ForgeRegistries.BLOCK_ENTITY_TYPES, OverdriveThatMatters.MOD_ID)

	val ANDROID_STATION: BlockEntityType<AndroidStationBlockEntity> by registry.register(MNames.ANDROID_STATION) { BlockEntityType.Builder.of(::AndroidStationBlockEntity, MBlocks.ANDROID_STATION).build(null) }
	val BATTERY_BANK: BlockEntityType<BatteryBankBlockEntity> by registry.register(MNames.BATTERY_BANK) { BlockEntityType.Builder.of(::BatteryBankBlockEntity, MBlocks.BATTERY_BANK).build(null) }
	val MATTER_DECOMPOSER: BlockEntityType<MatterDecomposerBlockEntity> by registry.register(MNames.MATTER_DECOMPOSER) { BlockEntityType.Builder.of(::MatterDecomposerBlockEntity, MBlocks.MATTER_DECOMPOSER).build(null) }
	val MATTER_CAPACITOR_BANK: BlockEntityType<MatterCapacitorBankBlockEntity> by registry.register(MNames.MATTER_CAPACITOR_BANK) { BlockEntityType.Builder.of(::MatterCapacitorBankBlockEntity, MBlocks.MATTER_CAPACITOR_BANK).build(null) }
	val MATTER_CABLE: BlockEntityType<MatterCableBlockEntity> by registry.register(MNames.MATTER_CABLE) { BlockEntityType.Builder.of(::MatterCableBlockEntity, MBlocks.MATTER_CABLE).build(null) }
	val STORAGE_CABLE: BlockEntityType<StorageCableBlockEntity> by registry.register(MNames.STORAGE_CABLE) { BlockEntityType.Builder.of(::StorageCableBlockEntity, MBlocks.STORAGE_CABLE).build(null) }
	val PATTERN_STORAGE: BlockEntityType<PatternStorageBlockEntity> by registry.register(MNames.PATTERN_STORAGE) { BlockEntityType.Builder.of(::PatternStorageBlockEntity, MBlocks.PATTERN_STORAGE).build(null) }
	val MATTER_SCANNER: BlockEntityType<MatterScannerBlockEntity> by registry.register(MNames.MATTER_SCANNER) { BlockEntityType.Builder.of(::MatterScannerBlockEntity, MBlocks.MATTER_SCANNER).build(null) }
	val MATTER_PANEL: BlockEntityType<MatterPanelBlockEntity> by registry.register(MNames.MATTER_PANEL) { BlockEntityType.Builder.of(::MatterPanelBlockEntity, MBlocks.MATTER_PANEL).build(null) }
	val MATTER_REPLICATOR: BlockEntityType<MatterReplicatorBlockEntity> by registry.register(MNames.MATTER_REPLICATOR) { BlockEntityType.Builder.of(::MatterReplicatorBlockEntity, MBlocks.MATTER_REPLICATOR).build(null) }
	val MATTER_BOTTLER: BlockEntityType<MatterBottlerBlockEntity> by registry.register(MNames.MATTER_BOTTLER) { BlockEntityType.Builder.of(::MatterBottlerBlockEntity, MBlocks.MATTER_BOTTLER).build(null) }
	val DRIVE_VIEWER: BlockEntityType<DriveViewerBlockEntity> by registry.register(MNames.DRIVE_VIEWER) { BlockEntityType.Builder.of(::DriveViewerBlockEntity, MBlocks.DRIVE_VIEWER).build(null) }
	val BLACK_HOLE: BlockEntityType<BlackHoleBlockEntity> by registry.register(MNames.BLACK_HOLE) { BlockEntityType.Builder.of(::BlackHoleBlockEntity, MBlocks.BLACK_HOLE).build(null) }
	val CARGO_CRATE: BlockEntityType<CargoCrateBlockEntity> by registry.register(MNames.CARGO_CRATE) { BlockEntityType.Builder.of(::CargoCrateBlockEntity, *MRegistry.CARGO_CRATES.blocks.values.toTypedArray()).build(null) }
	val DRIVE_RACK: BlockEntityType<DriveRackBlockEntity> by registry.register(MNames.DRIVE_RACK) { BlockEntityType.Builder.of(::DriveRackBlockEntity, MBlocks.DRIVE_RACK).build(null) }
	val ITEM_MONITOR: BlockEntityType<ItemMonitorBlockEntity> by registry.register(MNames.ITEM_MONITOR) { BlockEntityType.Builder.of(::ItemMonitorBlockEntity, MBlocks.ITEM_MONITOR).build(null) }
	val ENERGY_COUNTER: BlockEntityType<EnergyCounterBlockEntity> by registry.register(MNames.ENERGY_COUNTER) { BlockEntityType.Builder.of(::EnergyCounterBlockEntity, MBlocks.ENERGY_COUNTER).build(null) }
	val CHEMICAL_GENERATOR: BlockEntityType<ChemicalGeneratorBlockEntity> by registry.register(MNames.CHEMICAL_GENERATOR) { BlockEntityType.Builder.of(::ChemicalGeneratorBlockEntity, MBlocks.CHEMICAL_GENERATOR).build(null) }
	val PLATE_PRESS: BlockEntityType<PlatePressBlockEntity> by registry.register(MNames.PLATE_PRESS) { BlockEntityType.Builder.of(::PlatePressBlockEntity, MBlocks.PLATE_PRESS).build(null) }
	val TWIN_PLATE_PRESS: BlockEntityType<PlatePressBlockEntity> by registry.register(MNames.TWIN_PLATE_PRESS) { BlockEntityType.Builder.of({ a, b -> PlatePressBlockEntity(a, b, true) }, MBlocks.TWIN_PLATE_PRESS).build(null) }
	val GRAVITATION_STABILIZER: BlockEntityType<GravitationStabilizerBlockEntity> by registry.register(MNames.GRAVITATION_STABILIZER) { BlockEntityType.Builder.of(::GravitationStabilizerBlockEntity, MBlocks.GRAVITATION_STABILIZER).build(null) }
	val MATTER_RECYCLER: BlockEntityType<MatterRecyclerBlockEntity> by registry.register(MNames.MATTER_RECYCLER) { BlockEntityType.Builder.of(::MatterRecyclerBlockEntity, MBlocks.MATTER_RECYCLER).build(null) }
	val ENERGY_SERVO: BlockEntityType<EnergyServoBlockEntity> by registry.register(MNames.ENERGY_SERVO) { BlockEntityType.Builder.of(::EnergyServoBlockEntity, MBlocks.ENERGY_SERVO).build(null) }
	val COBBLESTONE_GENERATOR: BlockEntityType<CobblerBlockEntity> by registry.register(MNames.COBBLESTONE_GENERATOR) { BlockEntityType.Builder.of(::CobblerBlockEntity, MBlocks.COBBLESTONE_GENERATOR).build(null) }
	val ESSENCE_STORAGE: BlockEntityType<EssenceStorageBlockEntity> by registry.register(MNames.ESSENCE_STORAGE) { BlockEntityType.Builder.of(::EssenceStorageBlockEntity, MBlocks.ESSENCE_STORAGE).build(null) }
	val MATTER_RECONSTRUCTOR: BlockEntityType<MatterReconstructorBlockEntity> by registry.register(MNames.MATTER_RECONSTRUCTOR) { BlockEntityType.Builder.of(::MatterReconstructorBlockEntity, MBlocks.MATTER_RECONSTRUCTOR).build(null) }
	val FLUID_TANK: BlockEntityType<FluidTankBlockEntity> by registry.register(MNames.FLUID_TANK) { BlockEntityType.Builder.of(::FluidTankBlockEntity, MBlocks.FLUID_TANK).build(null) }
	val ANDROID_CHARGER: BlockEntityType<AndroidChargerBlockEntity> by registry.register(MNames.ANDROID_CHARGER) { BlockEntityType.Builder.of(::AndroidChargerBlockEntity, MBlocks.ANDROID_CHARGER).build(null) }
	val ANDROID_CHARGER_MIDDLE: BlockEntityType<AndroidChargerMiddleBlockEntity> by registry.register(MNames.ANDROID_CHARGER + "_middle") { BlockEntityType.Builder.of(::AndroidChargerMiddleBlockEntity, MBlocks.ANDROID_CHARGER).build(null) }
	val ANDROID_CHARGER_TOP: BlockEntityType<AndroidChargerTopBlockEntity> by registry.register(MNames.ANDROID_CHARGER + "_top") { BlockEntityType.Builder.of(::AndroidChargerTopBlockEntity, MBlocks.ANDROID_CHARGER).build(null) }

	val POWERED_FURNACE: BlockEntityType<PoweredFurnaceBlockEntity> by registry.register(MNames.POWERED_FURNACE) { BlockEntityType.Builder.of({ a, b -> MBlocks.POWERED_FURNACE.newBlockEntity(a, b) }, MBlocks.POWERED_FURNACE).build(null) }
	val POWERED_BLAST_FURNACE: BlockEntityType<PoweredFurnaceBlockEntity> by registry.register(MNames.POWERED_BLAST_FURNACE) { BlockEntityType.Builder.of({ a, b -> MBlocks.POWERED_BLAST_FURNACE.newBlockEntity(a, b) }, MBlocks.POWERED_BLAST_FURNACE).build(null) }
	val POWERED_SMOKER: BlockEntityType<PoweredFurnaceBlockEntity> by registry.register(MNames.POWERED_SMOKER) { BlockEntityType.Builder.of({ a, b -> MBlocks.POWERED_SMOKER.newBlockEntity(a, b) }, MBlocks.POWERED_SMOKER).build(null) }

	val STORAGE_BUS: BlockEntityType<StorageBusBlockEntity> by registry.register(MNames.STORAGE_BUS) { BlockEntityType.Builder.of(::StorageBusBlockEntity, MBlocks.STORAGE_BUS).build(null) }
	val STORAGE_IMPORTER: BlockEntityType<StorageImporterBlockEntity> by registry.register(MNames.STORAGE_IMPORTER) { BlockEntityType.Builder.of(::StorageImporterBlockEntity, MBlocks.STORAGE_IMPORTER).build(null) }
	val STORAGE_EXPORTER: BlockEntityType<StorageExporterBlockEntity> by registry.register(MNames.STORAGE_EXPORTER) { BlockEntityType.Builder.of(::StorageExporterBlockEntity, MBlocks.STORAGE_EXPORTER).build(null) }
	val STORAGE_POWER_SUPPLIER: BlockEntityType<StoragePowerSupplierBlockEntity> by registry.register(MNames.STORAGE_POWER_SUPPLIER) { BlockEntityType.Builder.of(::StoragePowerSupplierBlockEntity, MBlocks.STORAGE_POWER_SUPPLIER).build(null) }

	val HOLO_SIGN: BlockEntityType<HoloSignBlockEntity> by registry.register(MNames.HOLO_SIGN) { BlockEntityType.Builder.of(::HoloSignBlockEntity, MBlocks.HOLO_SIGN).build(null) }

	val DEBUG_EXPLOSION_SMALL: BlockEntityType<BlockEntityExplosionDebugger> by registry.register(MNames.DEBUG_EXPLOSION_SMALL) { BlockEntityType.Builder.of(::BlockEntityExplosionDebugger, MBlocks.DEBUG_EXPLOSION_SMALL).build(null) }
	val DEBUG_SPHERE_POINTS: BlockEntityType<BlockEntitySphereDebugger> by registry.register(MNames.DEBUG_SPHERE_POINTS) { BlockEntityType.Builder.of(::BlockEntitySphereDebugger, MBlocks.DEBUG_SPHERE_POINTS).build(null) }

	internal fun register(bus: IEventBus) {
		registry.register(bus)
		bus.addListener(this::registerClient)
	}

	@Suppress("unchecked_cast")
	private fun registerClient(event: FMLClientSetupEvent) {
		event.enqueueWork {
			BlockEntityRenderers.register(BLACK_HOLE, ::BlackHoleRenderer)
			BlockEntityRenderers.register(GRAVITATION_STABILIZER, ::GravitationStabilizerRenderer)
			BlockEntityRenderers.register(ENERGY_COUNTER, ::EnergyCounterRenderer)
			BlockEntityRenderers.register(BATTERY_BANK, ::BatteryBankRenderer)
			BlockEntityRenderers.register(MATTER_CAPACITOR_BANK, ::MatterBatteryBankRenderer)
			BlockEntityRenderers.register(MATTER_RECONSTRUCTOR, ::MatterReconstructorRenderer)
			BlockEntityRenderers.register(MATTER_REPLICATOR, ::MatterReplicatorRenderer)
			BlockEntityRenderers.register(MATTER_SCANNER, ::MatterScannerRenderer)
			BlockEntityRenderers.register(HOLO_SIGN, ::HoloSignRenderer)
			BlockEntityRenderers.register(FLUID_TANK, ::FluidTankRenderer)
		}
	}
}
