package ru.dbotthepony.mc.otm.datagen

import net.minecraft.world.item.DyeColor
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.neoforged.neoforge.client.model.generators.BlockModelBuilder
import net.neoforged.neoforge.client.model.generators.ConfiguredModel
import net.neoforged.neoforge.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.game.MBlocks
import ru.dbotthepony.mc.otm.registry.game.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.decorativeCubeAllCutout(MBlocks.METAL_MESH)

	DataGen.decoratives(MRegistry.TRITANIUM_BLOCK)

	for (color in DyeColor.entries) {
		blockModelProvider.exec {
			blockModelProvider.withExistingParent("block/tritanium_anvil0_${color.name.lowercase()}", "${DataGen.MOD_ID}:block/tritanium_anvil0")
				.texture("3", modLocation("block/tritanium_anvil/${color.name.lowercase()}"))
				.texture("particle", modLocation("block/tritanium_anvil/${color.name.lowercase()}"))
		}

		for (i in 1 until MBlocks.TRITANIUM_ANVIL_VARIANTS) {
			blockModelProvider.exec {
				blockModelProvider.withExistingParent("block/tritanium_anvil${i}_${color.name.lowercase()}", "${DataGen.MOD_ID}:block/tritanium_anvil$i")
					.texture("2", modLocation("block/tritanium_anvil_top/${color.name.lowercase()}"))
					.texture("3", modLocation("block/tritanium_anvil/${color.name.lowercase()}"))
					.texture("particle", modLocation("block/tritanium_anvil/${color.name.lowercase()}"))
			}
		}
	}

	for (anvils in MBlocks.TRITANIUM_ANVIL.values) {
		for (anvil in anvils) {
			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, 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,
				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,
				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,
			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,
			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)

	blockModelProvider.colored("computer_terminal", mapOf(
		"0" to "decorative/computer_base",
		"1" to "decorative/computer_screen",
		"particle" to "decorative/computer_base",
	))
	blockStateProvider.block(MRegistry.COMPUTER_TERMINAL.allBlocks.values)

	blockModelProvider.colored("star_chair", mapOf(
		"1" to "decorative/star_chair",
		"2" to "powered_smoker_base",
	))
	blockStateProvider.block(MRegistry.STAR_CHAIR.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.decorativePillar(MBlocks.METAL_BEAM, "metal_beam_side", "metal_beam_top")
	blockModelProvider.decorativeCubeAll(MBlocks.METAL_BEAM_CENTER, "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, MItems.DANGER_STRIPE_BLOCK.registryName!!.path + "_0")
	itemModelProvider.block(MItems.METAL_BEAM)

	blockStateProvider.block(MBlocks.METAL_BEAM_CENTER)
	itemModelProvider.block(MItems.METAL_BEAM_CENTER)

	blockStateProvider.exec {
		blockStateProvider.getVariantBuilder(MBlocks.LABORATORY_LAMP).forAllStates {
			return@forAllStates ConfiguredModel.builder()
				.modelFile(if (it[BlockStateProperties.LIT]) labLampOn!! else labLampOff!!)
				.rotationX(it[BlockRotationFreedom.DIRECTIONAL.property].front.xRotationBlockstateNorth())
				.rotationY(it[BlockRotationFreedom.DIRECTIONAL.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.DIRECTIONAL.property].front.xRotationBlockstateNorth())
				.rotationY(it[BlockRotationFreedom.DIRECTIONAL.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}")
		}
	}

	MBlocks.TRITANIUM_STRIPED_BLOCK.entries.forEach { (c, it) ->
		DataGen.decorativeColumn(it, "stripe/tritanium_striped_block_${c.name.lowercase()}", "tritanium_block")
	}

	MBlocks.TRITANIUM_STRIPED_STAIRS.entries.forEach { (c, it) ->
		DataGen.decorativeStairs(it, "stripe/tritanium_striped_block_${c.name.lowercase()}", "tritanium_block")
	}

	MBlocks.TRITANIUM_STRIPED_WALL.entries.forEach { (c, it) ->
		DataGen.decorativeWall(it, "stripe/tritanium_striped_block_${c.name.lowercase()}", "tritanium_block")
	}

	MBlocks.TRITANIUM_STRIPED_SLAB.entries.forEach { (c, it) ->
		DataGen.decorativeSlab(it, MBlocks.TRITANIUM_STRIPED_BLOCK[c]!!.registryName!!, "stripe/tritanium_striped_block_${c.name.lowercase()}", "tritanium_block")
	}

	itemModelProvider.blocks(MItems.TRITANIUM_STRIPED_STAIRS.values)
	itemModelProvider.blocks(MItems.TRITANIUM_STRIPED_SLAB.values)

	itemModelProvider.exec {
		MBlocks.TRITANIUM_STRIPED_WALL.entries.forEach { (c, it) ->
			itemModelProvider.withExistingParent(it.registryName!!.path, modLocation("block/wall_inventory"))
				.texture("wall_side", modLocation("${DataGen.DECORATIVE_BLOCK_LOCATION}/stripe/tritanium_striped_block_${c.name.lowercase()}"))
				.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"))
	DataGen.bars(MBlocks.METAL_RAILING, modLocation("block/decorative/metal_railing"))

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