package ru.dbotthepony.mc.otm.registry

import net.minecraft.util.valueproviders.UniformInt
import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.crafting.RecipeType
import net.minecraft.world.level.block.AnvilBlock
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.DropExperienceBlock
import net.minecraft.world.level.block.IronBarsBlock
import net.minecraft.world.level.block.LiquidBlock
import net.minecraft.world.level.block.RotatedPillarBlock
import net.minecraft.world.level.block.SlabBlock
import net.minecraft.world.level.block.SoundType
import net.minecraft.world.level.block.StairBlock
import net.minecraft.world.level.block.WallBlock
import net.minecraft.world.level.block.state.BlockBehaviour
import net.minecraft.world.level.block.state.properties.NoteBlockInstrument
import net.minecraft.world.level.material.MapColor
import net.minecraft.world.level.material.PushReaction
import net.minecraftforge.eventbus.api.IEventBus
import net.minecraftforge.registries.DeferredRegister
import net.minecraftforge.registries.ForgeRegistries
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.block.BlackHoleBlock
import ru.dbotthepony.mc.otm.block.BlockExplosionDebugger
import ru.dbotthepony.mc.otm.block.BlockSphereDebugger
import ru.dbotthepony.mc.otm.block.EnergyCableBlock
import ru.dbotthepony.mc.otm.block.MatterCableBlock
import ru.dbotthepony.mc.otm.block.MatteryBlock
import ru.dbotthepony.mc.otm.block.StorageCableBlock
import ru.dbotthepony.mc.otm.block.addSimpleDescription
import ru.dbotthepony.mc.otm.block.decorative.DevChestBlock
import ru.dbotthepony.mc.otm.block.decorative.EngineBlock
import ru.dbotthepony.mc.otm.block.decorative.FluidTankBlock
import ru.dbotthepony.mc.otm.block.decorative.HoloSignBlock
import ru.dbotthepony.mc.otm.block.decorative.InfiniteWaterSourceBlock
import ru.dbotthepony.mc.otm.block.decorative.LaboratoryLamp
import ru.dbotthepony.mc.otm.block.decorative.LaboratoryLampLight
import ru.dbotthepony.mc.otm.block.decorative.PainterBlock
import ru.dbotthepony.mc.otm.block.decorative.TritaniumDoorBlock
import ru.dbotthepony.mc.otm.block.decorative.TritaniumTrapdoorBlock
import ru.dbotthepony.mc.otm.block.matter.MatterBottlerBlock
import ru.dbotthepony.mc.otm.block.matter.MatterCapacitorBankBlock
import ru.dbotthepony.mc.otm.block.matter.MatterDecomposerBlock
import ru.dbotthepony.mc.otm.block.matter.MatterEntanglerBlock
import ru.dbotthepony.mc.otm.block.matter.MatterPanelBlock
import ru.dbotthepony.mc.otm.block.matter.MatterReconstructorBlock
import ru.dbotthepony.mc.otm.block.matter.MatterRecyclerBlock
import ru.dbotthepony.mc.otm.block.matter.MatterReplicatorBlock
import ru.dbotthepony.mc.otm.block.matter.MatterScannerBlock
import ru.dbotthepony.mc.otm.block.matter.PatternStorageBlock
import ru.dbotthepony.mc.otm.block.storage.DriveRackBlock
import ru.dbotthepony.mc.otm.block.storage.DriveViewerBlock
import ru.dbotthepony.mc.otm.block.storage.ItemMonitorBlock
import ru.dbotthepony.mc.otm.block.storage.StorageBusBlock
import ru.dbotthepony.mc.otm.block.storage.StorageExporterBlock
import ru.dbotthepony.mc.otm.block.storage.StorageImporterBlock
import ru.dbotthepony.mc.otm.block.storage.StoragePowerSupplierBlock
import ru.dbotthepony.mc.otm.block.tech.AndroidChargerBlock
import ru.dbotthepony.mc.otm.block.tech.AndroidStationBlock
import ru.dbotthepony.mc.otm.block.tech.BatteryBankBlock
import ru.dbotthepony.mc.otm.block.tech.BlockGravitationStabilizer
import ru.dbotthepony.mc.otm.block.tech.BlockGravitationStabilizerLens
import ru.dbotthepony.mc.otm.block.tech.ChemicalGeneratorBlock
import ru.dbotthepony.mc.otm.block.tech.CobblerBlock
import ru.dbotthepony.mc.otm.block.tech.EnergyCounterBlock
import ru.dbotthepony.mc.otm.block.tech.EnergyServoBlock
import ru.dbotthepony.mc.otm.block.tech.EssenceStorageBlock
import ru.dbotthepony.mc.otm.block.tech.PhantomAttractorBlock
import ru.dbotthepony.mc.otm.block.tech.PlatePressBlock
import ru.dbotthepony.mc.otm.block.tech.AbstractPoweredFurnaceBlock
import ru.dbotthepony.mc.otm.block.tech.PoweredBlastFurnaceBlock
import ru.dbotthepony.mc.otm.block.tech.PoweredFurnaceBlock
import ru.dbotthepony.mc.otm.block.tech.PoweredSmokerBlock
import ru.dbotthepony.mc.otm.config.CablesConfig
import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.core.collect.SupplierList
import ru.dbotthepony.mc.otm.core.collect.SupplierMap
import ru.dbotthepony.mc.otm.shapes.BlockShapes
import java.util.function.Supplier

object MBlocks {
	private val registry = MDeferredRegister(ForgeRegistries.BLOCKS)

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

	val ANDROID_STATION = registry.coloredWithBase(MNames.ANDROID_STATION, ::AndroidStationBlock)
	val ANDROID_CHARGER = registry.coloredWithBase(MNames.ANDROID_CHARGER, ::AndroidChargerBlock)
	val BATTERY_BANK = registry.coloredWithBase(MNames.BATTERY_BANK, ::BatteryBankBlock)
	val MATTER_DECOMPOSER = registry.coloredWithBase(MNames.MATTER_DECOMPOSER, ::MatterDecomposerBlock)
	val MATTER_CAPACITOR_BANK = registry.coloredWithBase(MNames.MATTER_CAPACITOR_BANK, ::MatterCapacitorBankBlock)
	val MATTER_CABLE by registry.register(MNames.MATTER_CABLE, ::MatterCableBlock)
	val PATTERN_STORAGE by registry.register(MNames.PATTERN_STORAGE, ::PatternStorageBlock)
	val MATTER_SCANNER = registry.coloredWithBase(MNames.MATTER_SCANNER, ::MatterScannerBlock)
	val MATTER_PANEL = registry.coloredWithBase(MNames.MATTER_PANEL, ::MatterPanelBlock)
	val MATTER_REPLICATOR = registry.coloredWithBase(MNames.MATTER_REPLICATOR, ::MatterReplicatorBlock)
	val MATTER_BOTTLER = registry.coloredWithBase(MNames.MATTER_BOTTLER, ::MatterBottlerBlock)
	val ENERGY_COUNTER = registry.coloredWithBase(MNames.ENERGY_COUNTER, ::EnergyCounterBlock)
	val CHEMICAL_GENERATOR = registry.coloredWithBase(MNames.CHEMICAL_GENERATOR, ::ChemicalGeneratorBlock)
	val PLATE_PRESS = registry.coloredWithBase(MNames.PLATE_PRESS, ::PlatePressBlock)
	val TWIN_PLATE_PRESS = registry.coloredWithBase(MNames.TWIN_PLATE_PRESS) { color -> PlatePressBlock(color, isTwin = true) }
	val POWERED_FURNACE = registry.coloredWithBase(MNames.POWERED_FURNACE, ::PoweredFurnaceBlock)
	val POWERED_BLAST_FURNACE = registry.coloredWithBase(MNames.POWERED_BLAST_FURNACE, ::PoweredBlastFurnaceBlock)
	val POWERED_SMOKER = registry.coloredWithBase(MNames.POWERED_SMOKER, ::PoweredSmokerBlock)
	val MATTER_RECYCLER = registry.coloredWithBase(MNames.MATTER_RECYCLER, ::MatterRecyclerBlock)
	val ENERGY_SERVO = registry.coloredWithBase(MNames.ENERGY_SERVO, ::EnergyServoBlock)
	val COBBLESTONE_GENERATOR = registry.coloredWithBase(MNames.COBBLESTONE_GENERATOR, ::CobblerBlock)
	val INFINITE_WATER_SOURCE by registry.register(MNames.INFINITE_WATER_SOURCE) { InfiniteWaterSourceBlock() }
	val ESSENCE_STORAGE = registry.coloredWithBase(MNames.ESSENCE_STORAGE, ::EssenceStorageBlock)
	val MATTER_RECONSTRUCTOR = registry.coloredWithBase(MNames.MATTER_RECONSTRUCTOR, ::MatterReconstructorBlock)
	val PAINTER by registry.register(MNames.PAINTER, ::PainterBlock)
	val MATTER_ENTANGLER: MatterEntanglerBlock by registry.register(MNames.MATTER_ENTANGLER) { MatterEntanglerBlock() }

	val ENERGY_CABLES: Map<CablesConfig.E, EnergyCableBlock> = SupplierMap(CablesConfig.E.entries.map { conf ->
		conf to registry.register("${conf.name.lowercase()}_energy_cable") { EnergyCableBlock { a, b -> MBlockEntities.ENERGY_CABLES[conf]!!.create(a, b)!! } }
	})

	val STORAGE_BUS: Block by registry.register(MNames.STORAGE_BUS, ::StorageBusBlock)
	val STORAGE_IMPORTER: Block by registry.register(MNames.STORAGE_IMPORTER, ::StorageImporterBlock)
	val STORAGE_EXPORTER: Block by registry.register(MNames.STORAGE_EXPORTER, ::StorageExporterBlock)

	val DRIVE_VIEWER = registry.coloredWithBase(MNames.DRIVE_VIEWER, ::DriveViewerBlock)
	val DRIVE_RACK: Block by registry.register(MNames.DRIVE_RACK, ::DriveRackBlock)
	val ITEM_MONITOR = registry.coloredWithBase(MNames.ITEM_MONITOR, ::ItemMonitorBlock)
	val STORAGE_CABLE: Block by registry.register(MNames.STORAGE_CABLE, ::StorageCableBlock)
	val STORAGE_POWER_SUPPLIER = registry.coloredWithBase(MNames.STORAGE_POWER_SUPPLIER, ::StoragePowerSupplierBlock)

	val DEBUG_EXPLOSION_SMALL: Block by registry.register(MNames.DEBUG_EXPLOSION_SMALL) { BlockExplosionDebugger() }
	val DEBUG_SPHERE_POINTS: Block by registry.register(MNames.DEBUG_SPHERE_POINTS) { BlockSphereDebugger() }

	val BLACK_HOLE: Block by registry.register(MNames.BLACK_HOLE) { BlackHoleBlock() }
	val GRAVITATION_STABILIZER: Block by registry.register(MNames.GRAVITATION_STABILIZER) { BlockGravitationStabilizer() }
	val GRAVITATION_STABILIZER_LENS: Block by registry.register(MNames.GRAVITATION_STABILIZER_LENS) { BlockGravitationStabilizerLens() }

	val PHANTOM_ATTRACTOR: Block by registry.register(MNames.PHANTOM_ATTRACTOR) { PhantomAttractorBlock() }
	val FLUID_TANK: FluidTankBlock by registry.register(MNames.FLUID_TANK) { FluidTankBlock() }
	val DEV_CHEST: DevChestBlock by registry.register(MNames.DEV_CHEST) { DevChestBlock() }

	val LIQUID_XP: LiquidBlock by registry.register("liquid_xp") { LiquidBlock(MFluids::LIQUID_XP, BlockBehaviour.Properties.of().mapColor(MapColor.EMERALD).replaceable().noCollission().strength(100.0f).pushReaction(PushReaction.DESTROY).noLootTable().liquid().sound(SoundType.EMPTY)) }

	val TRITANIUM_ORE: Block by registry.register(MNames.TRITANIUM_ORE) { DropExperienceBlock(
		BlockBehaviour.Properties.of()
			.mapColor(MapColor.STONE)
			.strength(3.25f, 6.0f)
			.requiresCorrectToolForDrops(),
		UniformInt.of(0, 3)
	) }

	val TRITANIUM_INGOT_BLOCK: Block by registry.register(MNames.TRITANIUM_INGOT_BLOCK) {
		Block(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLUE).sound(SoundType.METAL).explosionResistance(400f).destroyTime(3f).requiresCorrectToolForDrops())
	}

	val METAL_JUNK: MatteryBlock by registry.register(MNames.METAL_JUNK) {
		 MatteryBlock(BlockBehaviour.Properties.of().sound(SoundType.NETHERITE_BLOCK).mapColor(MapColor.COLOR_GRAY).explosionResistance(45f).destroyTime(3f).requiresCorrectToolForDrops())
			 .addSimpleDescription()
	}

	val METAL_MESH: Block by registry.register(MNames.METAL_MESH) {
		Block(BlockBehaviour.Properties.of()
				.mapColor(MapColor.COLOR_GRAY)
				.noOcclusion()
				.sound(SoundType.COPPER).explosionResistance(30f)
				.destroyTime(2f).requiresCorrectToolForDrops())
	}

	val TRITANIUM_BARS: IronBarsBlock by registry.register(MNames.TRITANIUM_BARS) {
		IronBarsBlock(BlockBehaviour.Properties.of()
					.mapColor(MapColor.COLOR_LIGHT_BLUE)
					.sound(SoundType.METAL)
					.explosionResistance(45f)
					.noOcclusion()
					.destroyTime(2.5f)
					.requiresCorrectToolForDrops())
	}

	val DEEPSLATE_TRITANIUM_ORE: Block by registry.register(MNames.DEEPSLATE_TRITANIUM_ORE) { DropExperienceBlock(
		BlockBehaviour.Properties.of()
			.mapColor(MapColor.DEEPSLATE)
			.sound(SoundType.DEEPSLATE)
			.strength(4.75f, 6.5f)
			.requiresCorrectToolForDrops().sound(SoundType.DEEPSLATE),
		UniformInt.of(0, 3)
	) }

	val TRITANIUM_RAW_BLOCK: Block by registry.register(MNames.TRITANIUM_RAW_BLOCK) { Block(
		BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_LIGHT_BLUE).instrument(NoteBlockInstrument.BASEDRUM).strength(8.0f, 10f).requiresCorrectToolForDrops()
	) }

	val LABORATORY_LAMP: Block by registry.register(MNames.LABORATORY_LAMP) { LaboratoryLamp(false) }
	val LABORATORY_LAMP_INVERTED: Block by registry.register(MNames.LABORATORY_LAMP_INVERTED) { LaboratoryLamp(true) }
	val LABORATORY_LAMP_LIGHT: Block by registry.register(MNames.LABORATORY_LAMP_LIGHT) { LaboratoryLampLight() }
	val DANGER_STRIPE_BLOCK: Block by registry.register(MNames.DANGER_STRIPE_BLOCK) { Block(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_GRAY).explosionResistance(6f).destroyTime(1.5f).requiresCorrectToolForDrops()) }
	val METAL_BEAM: Block by registry.register(MNames.METAL_BEAM) { RotatedPillarBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_GRAY).sound(SoundType.METAL).explosionResistance(14f).destroyTime(2.5f).requiresCorrectToolForDrops()) }
	val ENGINE: Block by registry.register(MNames.ENGINE) { EngineBlock() }
	val HOLO_SIGN: Block by registry.register(MNames.HOLO_SIGN) { HoloSignBlock() }

	const val TRITANIUM_ANVIL_VARIANTS = 7

	val TRITANIUM_ANVIL: List<Block>

	init {
		val anvils = ArrayList<Supplier<Block>>()

		for (i in 0 until TRITANIUM_ANVIL_VARIANTS) {
			val props = BlockBehaviour.Properties.of()
				.mapColor(MapColor.COLOR_LIGHT_BLUE)
				.sound(SoundType.ANVIL)
				.destroyTime(2.5f - i * 0.15f)
				.explosionResistance(1200f - i * 80f)
				.pushReaction(PushReaction.BLOCK)
				.requiresCorrectToolForDrops()

			anvils.add(registry.register(MNames.TRITANIUM_ANVIL + i) { AnvilBlock(props) }::get)
		}

		TRITANIUM_ANVIL = SupplierList(anvils)
	}

	val TRITANIUM_DOOR = registry.coloredWithBase(MNames.TRITANIUM_DOOR, ::TritaniumDoorBlock)

	val TRITANIUM_TRAPDOOR = registry.coloredWithBase(MNames.TRITANIUM_TRAPDOOR, ::TritaniumTrapdoorBlock)

	val TRITANIUM_STRIPED_BLOCK: Block by registry.register(MNames.TRITANIUM_STRIPED_BLOCK, true) { Block(
		BlockBehaviour.Properties.of()
			.mapColor(MapColor.COLOR_LIGHT_BLUE)
			.sound(SoundType.BASALT)
			.requiresCorrectToolForDrops()
			.explosionResistance(80f)
			.strength(4f)
	) }

	val TRITANIUM_STRIPED_STAIRS: Block by registry.register(MNames.TRITANIUM_STRIPED_STAIRS) { StairBlock(
		{ TRITANIUM_STRIPED_BLOCK.defaultBlockState() },
		BlockBehaviour.Properties.copy(TRITANIUM_STRIPED_BLOCK)
	) }

	val TRITANIUM_STRIPED_SLAB: Block by registry.register(MNames.TRITANIUM_STRIPED_SLAB) {
		SlabBlock(BlockBehaviour.Properties.copy(TRITANIUM_STRIPED_BLOCK))
	}

	val TRITANIUM_STRIPED_WALL: Block by registry.register(MNames.TRITANIUM_STRIPED_WALL) {
		WallBlock(BlockBehaviour.Properties.copy(TRITANIUM_STRIPED_BLOCK))
	}

	val CARBON_FIBRE_BLOCK: Block by registry.register(MNames.CARBON_FIBRE_BLOCK) { Block(
		BlockBehaviour.Properties.of()
			.mapColor(MapColor.COLOR_GRAY)
			.sound(SoundType.BASALT)
			.requiresCorrectToolForDrops()
			.explosionResistance(40f)
			.strength(3f)
	) }

	init {
		MRegistry.registerBlocks(registry)
	}
}
