package ru.dbotthepony.mc.otm.datagen.blocks

import net.minecraft.world.level.block.state.properties.BlockStateProperties
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf
import net.neoforged.neoforge.client.model.generators.ConfiguredModel
import ru.dbotthepony.mc.otm.block.CableBlock
import ru.dbotthepony.mc.otm.block.decorative.CargoCrateBlock
import ru.dbotthepony.mc.otm.block.entity.WorkerState
import ru.dbotthepony.mc.otm.block.matter.MatterBottlerBlock
import ru.dbotthepony.mc.otm.block.tech.AndroidChargerBlock
import ru.dbotthepony.mc.otm.block.tech.EssenceStorageBlock
import ru.dbotthepony.mc.otm.core.ResourceLocation
import ru.dbotthepony.mc.otm.core.get
import ru.dbotthepony.mc.otm.core.math.BlockRotationFreedom
import ru.dbotthepony.mc.otm.core.math.xRotationBlockstateNorth
import ru.dbotthepony.mc.otm.core.math.xRotationBlockstateSouth
import ru.dbotthepony.mc.otm.core.math.yRotationBlockstateNorth
import ru.dbotthepony.mc.otm.core.math.yRotationBlockstateSouth
import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.datagen.modLocation
import ru.dbotthepony.mc.otm.registry.game.MBlocks
import ru.dbotthepony.mc.otm.registry.MNames
import ru.dbotthepony.mc.otm.registry.MRegistry
import java.util.ArrayList

fun addBlockStates(provider: MatteryBlockStateProvider) {
	provider.block(MBlocks.BLACK_HOLE)
	provider.block(MBlocks.ANDROID_STATION.values)

	provider.ore(MBlocks.DEEPSLATE_TRITANIUM_ORE)
	provider.ore(MBlocks.TRITANIUM_ORE)
	provider.ore(MBlocks.TRITANIUM_RAW_BLOCK)
	provider.block(MBlocks.TRITANIUM_INGOT_BLOCK)

	provider.block(MBlocks.WITHERED_STEEL_BLOCK)
	provider.exec {
		provider.getVariantBuilder(MBlocks.ROFLITE_ALLOY_BLOCK).forAllStates {
			val side1 = modLocation("block/resource/roflite_alloy_1")
			val side2 = modLocation("block/resource/roflite_alloy_2")
			val top = modLocation("block/resource/roflite_alloy_top")

			val a = provider.models().cube(MBlocks.ROFLITE_ALLOY_BLOCK.registryName!!.path, top, top, side1, side1, side2, side2).texture("particle", side1)
			val b = provider.models().cube("${MBlocks.ROFLITE_ALLOY_BLOCK.registryName!!.path}_b", top, top, side2, side2, side1, side1).texture("particle", side2)

			return@forAllStates arrayOf(ConfiguredModel.builder().modelFile(a).buildLast(), ConfiguredModel.builder().modelFile(b).buildLast())
		}
	}

	provider.ore(MBlocks.DILITHIUM_ORE)
	provider.ore(MBlocks.DEEPSLATE_DILITHIUM_ORE)
	provider.block(MBlocks.DILITHIUM_CRYSTAL_BLOCK)

	provider.block(MBlocks.CHEMICAL_GENERATOR.values)
	provider.block(MBlocks.MATTER_SCANNER.values)
	provider.block(MBlocks.ITEM_MONITOR.values)
	provider.block(MBlocks.HOLO_SIGN)

	provider.exec {
		with(provider.getMultipartBuilder(MBlocks.PHANTOM_ATTRACTOR)) {
			for (dir in BlockRotationFreedom.HORIZONTAL.possibleValues) {
				part().modelFile(provider.models().getExistingFile(modLocation("block/${MNames.PHANTOM_ATTRACTOR}")))
					.rotationY(dir.front.yRotationBlockstateNorth())
					.addModel()
					.condition(BlockStateProperties.DOUBLE_BLOCK_HALF, DoubleBlockHalf.LOWER)
					.condition(BlockRotationFreedom.HORIZONTAL.property, dir)
					.end()
			}
		}

		for (block in MBlocks.ANDROID_CHARGER.values) {
			with(provider.getMultipartBuilder(block)) {
				for (dir in BlockRotationFreedom.HORIZONTAL.possibleValues) {
					for (part in AndroidChargerBlock.PART.possibleValues) {
						part().modelFile(provider.models().getExistingFile(modLocation("block/${block.registryName!!.path}_${part.serializedName}")))
							.rotationY(dir.front.yRotationBlockstateNorth())
							.addModel()
							.condition(AndroidChargerBlock.PART, part)
							.condition(BlockRotationFreedom.HORIZONTAL.property, dir)
							.end()
					}
				}
			}
		}

		for (block in MBlocks.MATTER_BOTTLER.values) {
			with(provider.getMultipartBuilder(block)) {
				for (dir in BlockRotationFreedom.HORIZONTAL.possibleValues) {
					for (enum in WorkerState.SEMI_WORKER_STATE.possibleValues) {
						part().modelFile(provider.models().getExistingFile(modLocation("matter_bottler_${enum.name.lowercase()}")))
							.rotationY(dir.front.yRotationBlockstateNorth())
							.addModel()
							.condition(BlockRotationFreedom.HORIZONTAL.property, dir)
							.condition(WorkerState.WORKER_STATE, enum)
							.end()
					}
				}

				for (dir in BlockRotationFreedom.HORIZONTAL.possibleValues) {
					for (enum in MatterBottlerBlock.SLOT_PROPERTIES) {
						part().modelFile(provider.models().getExistingFile(modLocation("matter_bottler_${enum.name}_open")))
							.rotationY(dir.front.yRotationBlockstateNorth())
							.addModel()
							.condition(BlockRotationFreedom.HORIZONTAL.property, dir)
							.condition(enum, false)
							.end()

						part().modelFile(provider.models().getExistingFile(modLocation("matter_bottler_${enum.name}_closed")))
							.rotationY(dir.front.yRotationBlockstateNorth())
							.addModel()
							.condition(BlockRotationFreedom.HORIZONTAL.property, dir)
							.condition(enum, true)
							.end()
					}
				}
			}
		}
	}

	provider.block(MBlocks.MATTER_DECOMPOSER.values)
	provider.block(MBlocks.MATTER_REPLICATOR.values)
	provider.block(MBlocks.MATTER_ENTANGLER)
	provider.block(MBlocks.PLATE_PRESS.values)
	provider.block(MBlocks.TWIN_PLATE_PRESS.values)
	provider.block(MBlocks.GRAVITATION_STABILIZER)
	provider.block(MBlocks.GRAVITATION_STABILIZER_LENS)

	provider.block(MBlocks.POWERED_BLAST_FURNACE.values)
	provider.block(MBlocks.POWERED_FURNACE.values)
	provider.block(MBlocks.POWERED_SMOKER.values)

	provider.block(MBlocks.STORAGE_POWER_SUPPLIER.values)
	provider.block(MBlocks.MATTER_PANEL.values)
	provider.block(MBlocks.MATTER_RECYCLER.values)
	provider.block(MBlocks.MATTER_RECONSTRUCTOR.values)
	provider.block(MBlocks.ENERGY_SERVO.values)
	provider.block(MBlocks.COBBLESTONE_GENERATOR.values)

	provider.block(MBlocks.DRIVE_RACK)

	provider.block(MBlocks.PAINTER)
	provider.block(MBlocks.INFINITE_WATER_SOURCE)

	provider.exec {
		provider.getVariantBuilder(MBlocks.REDSTONE_LAMP_INVERTED)
			.forAllStates {
				ConfiguredModel.builder()
					.modelFile(provider.models().getExistingFile(ResourceLocation("minecraft", "redstone_lamp${if (it[BlockStateProperties.LIT]) "" else "_on"}")))
					.build()
			}

		provider.getVariantBuilder(MBlocks.REINFORCED_REDSTONE_LAMP)
			.forAllStates {
				ConfiguredModel.builder()
					.modelFile(provider.models().getExistingFile(modLocation("reinforced_redstone_lamp${if (it[BlockStateProperties.LIT]) "_on" else ""}")))
					.build()
			}

		provider.getVariantBuilder(MBlocks.REINFORCED_REDSTONE_LAMP_INVERTED)
			.forAllStates {
				ConfiguredModel.builder()
					.modelFile(provider.models().getExistingFile(modLocation("reinforced_redstone_lamp${if (it[BlockStateProperties.LIT]) "" else "_on"}")))
					.build()
			}
	}

	provider.exec {
		for (block in MBlocks.ESSENCE_STORAGE.values) {
			provider.getVariantBuilder(block).forAllStates {
				return@forAllStates arrayOf(
					ConfiguredModel.builder()
						.modelFile(provider.models().getExistingFile(
							modLocation("${block.registryName!!.path}_${if (it.getValue(
									EssenceStorageBlock.FILLED)) "filled" else "empty"}")
						))
						.rotationY(it.getValue(BlockRotationFreedom.HORIZONTAL.property).front.yRotationBlockstateNorth())
						.buildLast()
				)
			}
		}
	}

	provider.exec {
		for (crate in MRegistry.CARGO_CRATES.allBlocks.values) {
			provider.getVariantBuilder(crate).forAllStates {
				return@forAllStates arrayOf(
					ConfiguredModel.builder()
						.modelFile(provider.models().getExistingFile(
							modLocation("${crate.registryName!!.path}_${if (it.getValue(
										CargoCrateBlock.IS_OPEN)) "open" else "closed"}")
						))
						.rotationY(it.getValue(BlockRotationFreedom.HORIZONTAL.property).front.yRotationBlockstateNorth())
						.buildLast()
				)
			}
		}

		with(provider.getMultipartBuilder(MBlocks.STORAGE_BUS)) {
			for (dir in BlockRotationFreedom.DIRECTIONAL.possibleValues) {
				part().modelFile(provider.models().getExistingFile(modLocation("storage_bus")))
					.rotationX(dir.front.xRotationBlockstateNorth())
					.rotationY(dir.front.yRotationBlockstateNorth())
					.addModel()
					.condition(BlockRotationFreedom.DIRECTIONAL.property, dir)
					.end()

				part().modelFile(provider.models().getExistingFile(modLocation("storage_cable_connection")))
					.rotationX(dir.front.xRotationBlockstateSouth())
					.rotationY(dir.front.yRotationBlockstateSouth())
					.addModel()
					.condition(CableBlock.MAPPING_CONNECTION_PROP[dir.front]!!, true)
					.end()
			}

			part().modelFile(provider.models().getExistingFile(modLocation("storage_cable_core")))
				.addModel().end()
		}

		with(provider.getMultipartBuilder(MBlocks.STORAGE_IMPORTER)) {
			for (dir in BlockRotationFreedom.DIRECTIONAL.possibleValues) {
				part().modelFile(provider.models().getExistingFile(modLocation("storage_importer")))
					.rotationX(dir.front.xRotationBlockstateNorth())
					.rotationY(dir.front.yRotationBlockstateNorth())
					.addModel()
					.condition(BlockRotationFreedom.DIRECTIONAL.property, dir)
					.end()

				part().modelFile(provider.models().getExistingFile(modLocation("storage_cable_connection")))
					.rotationX(dir.front.xRotationBlockstateSouth())
					.rotationY(dir.front.yRotationBlockstateSouth())
					.addModel()
					.condition(CableBlock.MAPPING_CONNECTION_PROP[dir.front]!!, true)
					.end()
			}

			part().modelFile(provider.models().getExistingFile(modLocation("storage_cable_core")))
				.addModel().end()
		}

		with(provider.getMultipartBuilder(MBlocks.STORAGE_EXPORTER)) {
			for (dir in BlockRotationFreedom.DIRECTIONAL.possibleValues) {
				part().modelFile(provider.models().getExistingFile(modLocation("storage_exporter")))
					.rotationX(dir.front.xRotationBlockstateNorth())
					.rotationY(dir.front.yRotationBlockstateNorth())
					.addModel()
					.condition(BlockRotationFreedom.DIRECTIONAL.property, dir)
					.end()

				part().modelFile(provider.models().getExistingFile(modLocation("storage_cable_connection")))
					.rotationX(dir.front.xRotationBlockstateSouth())
					.rotationY(dir.front.yRotationBlockstateSouth())
					.addModel()
					.condition(CableBlock.MAPPING_CONNECTION_PROP[dir.front]!!, true)
					.end()
			}

			part().modelFile(provider.models().getExistingFile(modLocation("storage_cable_core")))
				.addModel().end()
		}

		with(provider.getMultipartBuilder(MBlocks.MATTER_CABLE)) {
			for (dir in BlockRotationFreedom.DIRECTIONAL.possibleValues) {
				part().modelFile(provider.models().getExistingFile(modLocation("matter_cable_connection")))
					.rotationX(dir.front.xRotationBlockstateSouth())
					.rotationY(dir.front.yRotationBlockstateSouth())
					.addModel()
					.condition(CableBlock.MAPPING_CONNECTION_PROP[dir.front]!!, true)
					.end()
			}

			part().modelFile(provider.models().getExistingFile(modLocation("matter_cable_core")))
				.addModel().end()
		}

		with(provider.getMultipartBuilder(MBlocks.STORAGE_CABLE)) {
			for (dir in BlockRotationFreedom.DIRECTIONAL.possibleValues) {
				part().modelFile(provider.models().getExistingFile(modLocation("storage_cable_connection")))
					.rotationX(dir.front.xRotationBlockstateSouth())
					.rotationY(dir.front.yRotationBlockstateSouth())
					.addModel()
					.condition(CableBlock.MAPPING_CONNECTION_PROP[dir.front]!!, true)
					.end()
			}

			part().modelFile(provider.models().getExistingFile(modLocation("storage_cable_core")))
				.addModel().end()
		}

		for (block in MBlocks.ENERGY_CABLES) {
			with(provider.getMultipartBuilder(block.value)) {
				for (dir in BlockRotationFreedom.DIRECTIONAL.possibleValues) {
					part().modelFile(provider.models().getExistingFile(modLocation("${block.value.registryName!!.path}_connection")))
						.rotationX(dir.front.xRotationBlockstateSouth())
						.rotationY(dir.front.yRotationBlockstateSouth())
						.addModel()
						.condition(CableBlock.MAPPING_CONNECTION_PROP[dir.front]!!, true)
						.condition(BlockStateProperties.POWERED, false)
						.end()

					part().modelFile(provider.models().getExistingFile(modLocation("${block.value.registryName!!.path}_connection_powered")))
						.rotationX(dir.front.xRotationBlockstateSouth())
						.rotationY(dir.front.yRotationBlockstateSouth())
						.addModel()
						.condition(CableBlock.MAPPING_CONNECTION_PROP[dir.front]!!, true)
						.condition(BlockStateProperties.POWERED, true)
						.end()
				}

				part().modelFile(provider.models().getExistingFile(modLocation("${block.value.registryName!!.path}_core")))
					.addModel().condition(BlockStateProperties.POWERED, false).end()
				part().modelFile(provider.models().getExistingFile(modLocation("${block.value.registryName!!.path}_core_powered")))
					.addModel().condition(BlockStateProperties.POWERED, true).end()
			}
		}

		provider.getVariantBuilder(MBlocks.METAL_JUNK).forAllStates {
			val generated = ArrayList<ConfiguredModel>()

			for (suffix in arrayOf("_a", "_b", "_c", "_d")) {
				val model = provider.models().cubeAll("block/metal_junk$suffix", modLocation("block/decorative/metal_junk$suffix"))

				generated.add(with(ConfiguredModel.builder()) {
					modelFile(model)

					return@with buildLast()
				})

				generated.add(with(ConfiguredModel.builder()) {
					modelFile(model)
					rotationY(180)

					return@with buildLast()
				})
			}

			return@forAllStates generated.toTypedArray()
		}

		provider.getVariantBuilder(MBlocks.DANGER_STRIPE_BLOCK).forAllStates {
			val generated = ArrayList<ConfiguredModel>()

			for (suffix in arrayOf("_0", "_1")) {
				generated.add(with(ConfiguredModel.builder()) {
					modelFile(provider.models().cubeAll("block/danger_stripe_block$suffix", modLocation("block/decorative/danger_stripe_block$suffix")))

					return@with buildLast()
				})
			}

			return@forAllStates generated.toTypedArray()
		}
	}

	provider.block(MBlocks.TRITANIUM_HULL)

	provider.block(MBlocks.FLYWHEEL_HOUSING)
	provider.block(MBlocks.FLYWHEEL_BEARING)
	provider.block(MBlocks.FLYWHEEL_SHAFT)
	provider.block(MBlocks.FLYWHEEL_BATTERY)

	provider.block(MBlocks.GENERATOR_BLOCK)
	provider.block(MBlocks.MODULAR_FRAME)
	provider.block(MBlocks.HEAVY_MODULAR_FRAME)

	provider.block(MBlocks.ENERGY_INPUT_INTERFACE)
	provider.block(MBlocks.ENERGY_OUTPUT_INTERFACE)

	provider.block(MBlocks.ENERGY_INPUT_HATCH)
	provider.block(MBlocks.ENERGY_OUTPUT_HATCH)

	provider.block(MBlocks.MATTER_INPUT_HATCH)
	provider.block(MBlocks.MATTER_OUTPUT_HATCH)

	provider.block(MBlocks.ITEM_INPUT_HATCH)
	provider.block(MBlocks.ITEM_OUTPUT_HATCH)

}
