package ru.dbotthepony.mc.otm.datagen

import net.minecraft.world.level.block.AnvilBlock
import net.minecraft.world.level.block.SlabBlock
import net.minecraft.world.level.block.StairBlock
import net.minecraft.world.level.block.WallBlock
import net.minecraft.world.level.block.state.properties.BlockStateProperties
import net.minecraftforge.client.model.generators.BlockModelBuilder
import net.minecraftforge.client.model.generators.ConfiguredModel
import net.minecraftforge.client.model.generators.ModelFile
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.yRotationBlockstateNorth
import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.datagen.blocks.MatteryBlockStateProvider
import ru.dbotthepony.mc.otm.datagen.items.MatteryItemModelProvider
import ru.dbotthepony.mc.otm.datagen.models.MatteryBlockModelProvider
import ru.dbotthepony.mc.otm.registry.MBlocks
import ru.dbotthepony.mc.otm.registry.MItems
import ru.dbotthepony.mc.otm.registry.MNames
import ru.dbotthepony.mc.otm.registry.MRegistry
import kotlin.properties.Delegates

fun addDecorativeData(blockStateProvider: MatteryBlockStateProvider, itemModelProvider: MatteryItemModelProvider, blockModelProvider: MatteryBlockModelProvider) {
	for ((color, block) in MRegistry.DECORATIVE_CRATE.allBlocks) {
		if (color == null) {
			blockModelProvider.decorativeCubeAll(block, "crates/crate_colorless_borderless")
		} else {
			blockModelProvider.decorativeCubeAll(block, "crates/crate_borderless_${color.name.lowercase()}")
		}

		blockStateProvider.simpleBlockM(block)
	}

	DataGen.decorativeCubeAll(MBlocks.CARBON_FIBRE_BLOCK)

	DataGen.decoratives(MRegistry.TRITANIUM_BLOCK)

	for (anvil in MBlocks.TRITANIUM_ANVIL) {
		blockStateProvider.exec {
			blockStateProvider.getVariantBuilder(anvil).forAllStates {
				ConfiguredModel.builder()
					.modelFile(blockStateProvider.models().getExistingFile(modLocation("block/${anvil.registryName!!.path}")))
					.rotationY(it[AnvilBlock.FACING].yRotationBlockstateNorth())
					.build()
			}
		}
	}

	for ((color, block) in MRegistry.TRITANIUM_STAIRS.allBlocks) {
		DataGen.decorativeStairs(block as StairBlock, MRegistry.TRITANIUM_BLOCK.allBlocks[color]!!.registryName!!.path, MRegistry.TRITANIUM_BLOCK.allBlocks[color]!!.registryName!!.path)
	}

	for ((color, block) in MRegistry.TRITANIUM_PRESSURE_PLATE.allBlocks) {
		val texture = modLocation(DataGen.DECORATIVE_BLOCK_LOCATION + "/" + MRegistry.TRITANIUM_BLOCK.allBlocks[color]!!.registryName!!.path)

		var depressed by Delegates.notNull<ModelFile>()
		var pressed by Delegates.notNull<ModelFile>()

		blockModelProvider.exec {
			depressed = blockModelProvider.pressurePlate(block.registryName!!.path, texture)
			pressed = blockModelProvider.pressurePlateDown(block.registryName!!.path + "_pressed", texture)
		}

		blockStateProvider.exec {
			blockStateProvider.getVariantBuilder(block)
				.partialState().with(BlockStateProperties.POWERED, false).addModels(ConfiguredModel(depressed))
				.partialState().with(BlockStateProperties.POWERED, true).addModels(ConfiguredModel(pressed))
		}
	}

	for (item in MRegistry.TRITANIUM_PRESSURE_PLATE.allItems.values) {
		itemModelProvider.block(item)
	}

	for ((color, block) in MRegistry.TRITANIUM_SLAB.allBlocks) {
		blockStateProvider.exec {
			blockStateProvider.slabBlock(
				block as SlabBlock,
				MRegistry.TRITANIUM_BLOCK.allBlocks[color]!!.registryName!!,
				modLocation("${DataGen.DECORATIVE_BLOCK_LOCATION}/${MRegistry.TRITANIUM_BLOCK.allBlocks[color]!!.registryName!!.path}")
			)
		}
	}

	for ((color, block) in MRegistry.FLOOR_TILES_SLAB.blocks) {
		blockStateProvider.exec {
			blockStateProvider.slabBlock(
				block as SlabBlock,
				MRegistry.FLOOR_TILES.blocks[color]!!.registryName!!,
				modLocation("${DataGen.DECORATIVE_BLOCK_LOCATION}/${MRegistry.FLOOR_TILES.blocks[color]!!.registryName!!.path}")
			)
		}
	}

	for ((color, block) in MRegistry.FLOOR_TILES_STAIRS.blocks) {
		DataGen.decorativeStairs(
			block as StairBlock,
			MRegistry.FLOOR_TILES.blocks[color]!!.registryName!!.path,
			MRegistry.FLOOR_TILES.blocks[color]!!.registryName!!.path
		)
	}

	for ((color, block) in MRegistry.TRITANIUM_WALL.allBlocks) {
		DataGen.decorativeWall(
			block as WallBlock,
			sideTexture = MRegistry.TRITANIUM_BLOCK.allBlocks[color]!!.registryName!!.path,
			topTexture = MRegistry.TRITANIUM_BLOCK.allBlocks[color]!!.registryName!!.path
		)
	}

	for (item in MRegistry.TRITANIUM_STAIRS.allItems.values) {
		itemModelProvider.block(item)
	}

	for (item in MRegistry.TRITANIUM_SLAB.allItems.values) {
		itemModelProvider.block(item)
	}

	for (item in MRegistry.FLOOR_TILES_SLAB.items.values) {
		itemModelProvider.block(item)
	}

	for (item in MRegistry.FLOOR_TILES_STAIRS.items.values) {
		itemModelProvider.block(item)
	}

	for ((color, item) in MRegistry.TRITANIUM_WALL.allItems) {
		itemModelProvider.exec {
			itemModelProvider.wallInventory(item.registryName!!.path, modLocation(DataGen.DECORATIVE_BLOCK_LOCATION + "/" + MRegistry.TRITANIUM_BLOCK.allBlocks[color]!!.registryName!!.path))
		}
	}

	DataGen.decoratives(MRegistry.FLOOR_TILES)
	DataGen.decoratives(MRegistry.UNREFINED_FLOOR_TILES)
	DataGen.decoratives(MRegistry.VENT)
	DataGen.decoratives(MRegistry.VENT_ALTERNATIVE)

	blockModelProvider.decorativeGlassAll(MRegistry.INDUSTRIAL_GLASS.allBlocks.values)
	blockStateProvider.simpleBlockM(MRegistry.INDUSTRIAL_GLASS.allBlocks.values)

	blockStateProvider.simpleBlockM(MBlocks.FLUID_TANK)

	for ((block, colors) in MRegistry.TRITANIUM_STRIPED_BLOCK.blocksWithColor) {
		DataGen.decorativeColumn(
			block,
			"stripe/${block.registryName!!.path}",
			"tritanium_block_${colors.first.name.lowercase()}"
		)
	}

	for ((block, colors) in MRegistry.TRITANIUM_STRIPED_STAIRS.blocksWithColor) {
		DataGen.decorativeStairs(
			block as StairBlock,
			"stripe/${MRegistry.TRITANIUM_STRIPED_BLOCK.getBlock(colors.first, colors.second).registryName!!.path}",
			"tritanium_block_${colors.first.name.lowercase()}"
		)
	}

	for ((block, colors) in MRegistry.TRITANIUM_STRIPED_SLAB.blocksWithColor) {
		DataGen.decorativeSlab(
			block as SlabBlock,
			MRegistry.TRITANIUM_STRIPED_BLOCK.getBlock(colors.first, colors.second).registryName!!,
			"stripe/${MRegistry.TRITANIUM_STRIPED_BLOCK.getBlock(colors.first, colors.second).registryName!!.path}",
			"tritanium_block_${colors.first.name.lowercase()}"
		)
	}

	for ((block, colors) in MRegistry.TRITANIUM_STRIPED_WALL.blocksWithColor) {
		DataGen.decorativeWall(
			block as WallBlock,
			sideTexture = "stripe/${MRegistry.TRITANIUM_STRIPED_BLOCK.getBlock(colors.first, colors.second).registryName!!.path}",
			topTexture = "tritanium_block_${colors.first.name.lowercase()}"
		)
	}

	for (item in MRegistry.TRITANIUM_STRIPED_STAIRS.flatItems) {
		itemModelProvider.block(item)
	}

	for (item in MRegistry.TRITANIUM_STRIPED_SLAB.flatItems) {
		itemModelProvider.block(item)
	}

	for ((item, colors) in MRegistry.TRITANIUM_STRIPED_WALL.itemsWithColor) {
		itemModelProvider.exec {
			itemModelProvider.withExistingParent(item.registryName!!.path, modLocation("block/wall_inventory"))
				.texture("wall_side", modLocation("${DataGen.DECORATIVE_BLOCK_LOCATION}/stripe/${MRegistry.TRITANIUM_STRIPED_BLOCK.getBlock(colors.first, colors.second).registryName!!.path}"))
				.texture("wall", modLocation("${DataGen.DECORATIVE_BLOCK_LOCATION}/tritanium_block_${colors.first.name.lowercase()}"))
		}
	}

	DataGen.decorativeCubeAll(MBlocks.DANGER_STRIPE_BLOCK)
	DataGen.decorativeColumn(MBlocks.METAL_BEAM, "metal_beam_side", "metal_beam_top")

	var labLampOn: BlockModelBuilder? = null
	var labLampOff: BlockModelBuilder? = null

	blockModelProvider.exec {
		val top = modLocation("block/decorative/metal_beam_top")

		labLampOn = it.cube(
			MBlocks.LABORATORY_LAMP.registryName!!.path,
			top,
			top,
			modLocation("block/decorative/laboratory_lamp_front"),
			top,
			top,
			top,
		).texture("particle", top)

		labLampOff = it.cube(
			MBlocks.LABORATORY_LAMP.registryName!!.path + "_unlit",
			top,
			top,
			modLocation("block/decorative/laboratory_lamp_front_off"),
			top,
			top,
			top,
		).texture("particle", top)
	}

	itemModelProvider.block(MItems.LABORATORY_LAMP)
	itemModelProvider.block(MItems.LABORATORY_LAMP_INVERTED, MItems.LABORATORY_LAMP.registryName!!.path + "_unlit")
	itemModelProvider.block(MItems.DANGER_STRIPE_BLOCK)
	itemModelProvider.block(MItems.METAL_BEAM)

	blockStateProvider.exec {
		blockStateProvider.getVariantBuilder(MBlocks.LABORATORY_LAMP).forAllStates {
			return@forAllStates ConfiguredModel.builder()
				.modelFile(if (it[BlockStateProperties.LIT]) labLampOn!! else labLampOff!!)
				.rotationX(it[BlockRotationFreedom.TWO.property].front.xRotationBlockstateNorth())
				.rotationY(it[BlockRotationFreedom.TWO.property].front.yRotationBlockstateNorth())
				.build()
		}

		blockStateProvider.getVariantBuilder(MBlocks.LABORATORY_LAMP_INVERTED).forAllStates {
			return@forAllStates ConfiguredModel.builder()
				.modelFile(if (it[BlockStateProperties.LIT]) labLampOn!! else labLampOff!!)
				.rotationX(it[BlockRotationFreedom.TWO.property].front.xRotationBlockstateNorth())
				.rotationY(it[BlockRotationFreedom.TWO.property].front.yRotationBlockstateNorth())
				.build()
		}
	}

	blockModelProvider.exec {
		for (crate in MRegistry.CARGO_CRATES.blocks.values) {
			it.withExistingParent("${crate.registryName!!.path}_closed", modLocation("${MNames.CARGO_CRATE}_closed"))
				.texture("body", "block/cargo_crates/${crate.registryName!!.path}")
				.texture("particle", "block/cargo_crates/${crate.registryName!!.path}")

			it.withExistingParent("${crate.registryName!!.path}_open", modLocation("${MNames.CARGO_CRATE}_open"))
				.texture("body", "block/cargo_crates/${crate.registryName!!.path}")
				.texture("particle", "block/cargo_crates/${crate.registryName!!.path}")
		}
	}

	DataGen.decorativeColumn(MBlocks.TRITANIUM_STRIPED_BLOCK, "tritanium_striped_block", "tritanium_block")
	DataGen.decorativeStairs(MBlocks.TRITANIUM_STRIPED_STAIRS as StairBlock, "tritanium_striped_block", "tritanium_block")
	DataGen.decorativeWall(MBlocks.TRITANIUM_STRIPED_WALL as WallBlock, "tritanium_striped_block", "tritanium_block")
	DataGen.decorativeSlab(MBlocks.TRITANIUM_STRIPED_SLAB as SlabBlock, MBlocks.TRITANIUM_STRIPED_BLOCK.registryName!!, "tritanium_striped_block", "tritanium_block")
	itemModelProvider.block(MItems.TRITANIUM_STRIPED_STAIRS)
	itemModelProvider.block(MItems.TRITANIUM_STRIPED_SLAB)

	itemModelProvider.exec {
		itemModelProvider.withExistingParent(MItems.TRITANIUM_STRIPED_WALL.registryName!!.path, modLocation("block/wall_inventory"))
			.texture("wall_side", modLocation("${DataGen.DECORATIVE_BLOCK_LOCATION}/tritanium_striped_block"))
			.texture("wall", modLocation("${DataGen.DECORATIVE_BLOCK_LOCATION}/tritanium_block"))
	}

	for ((color, glass) in MRegistry.INDUSTRIAL_GLASS_PANE.allBlocks) {
		val name = MRegistry.INDUSTRIAL_GLASS.allBlocks[color]!!.registryName!!.path
		val textureSide = modLocation("block/decorative/$name")
		val textureRailing = modLocation("block/decorative/industrial_glass_frame")
		DataGen.pane(glass, textureSide, textureRailing)
	}

	DataGen.bars(MBlocks.TRITANIUM_BARS, modLocation("block/decorative/tritanium_bars"))

	blockStateProvider.block(MBlocks.ENGINE)
	itemModelProvider.block(MItems.ENGINE)
}
