package ru.dbotthepony.mc.otm.datagen.models

import net.minecraft.world.item.DyeColor
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.WaterloggedTransparentBlock
import net.neoforged.neoforge.client.model.generators.BlockModelProvider
import net.neoforged.neoforge.data.event.GatherDataEvent
import ru.dbotthepony.mc.otm.datagen.DataGen
import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.datagen.modLocation
import java.util.LinkedList

class MatteryBlockModelProvider(event: GatherDataEvent) : BlockModelProvider(event.generator.packOutput, DataGen.MOD_ID, event.existingFileHelper) {
	private val callbacks = LinkedList<(MatteryBlockModelProvider) -> Unit>()

	fun exec(callback: (MatteryBlockModelProvider) -> Unit) {
		callbacks.add(callback)
	}

	override fun registerModels() {
		for (callback in callbacks) {
			callback(this)
		}
	}

	override fun getName(): String {
		return "Block Models: $modid"
	}

	fun cubeAll(vararg blocks: Block) {
		for (block in blocks) {
			exec {
				cubeAll(block.registryName!!.path, modLocation("block/${block.registryName!!.path}"))
			}
		}
	}

	fun cubeAllCutout(vararg blocks: Block) {
		for (block in blocks) {
			exec {
				cubeAll(block.registryName!!.path, modLocation("block/${block.registryName!!.path}")).renderType("cutout_mipped")
			}
		}
	}

	fun cubeAllFramed(modelName: String, textureName: String) {
		exec {
			withExistingParent(modelName, modLocation("block/frame_block"))
				.texture("texture", textureName)
				.renderType("cutout_mipped")
		}
	}

	fun decorativeGlassAll(blocks: Collection<Block>) {
		for (block in blocks) {
			exec {
				cubeAll(block.registryName!!.path, modLocation("block/decorative/${block.registryName!!.path}")).renderType("translucent")
			}
		}
	}

	fun decorativeGlassAll(vararg blocks: Block) {
		for (block in blocks) {
			exec {
				cubeAll(block.registryName!!.path, modLocation("block/decorative/${block.registryName!!.path}")).renderType("translucent")
			}
		}
	}

	fun decorativeCubeAll(vararg blocks: Block) {
		for (block in blocks) {
			exec {
				cubeAll(block.registryName!!.path, modLocation("block/decorative/${block.registryName!!.path}"))
			}
		}
	}

	fun decorativeCubeAllCutout(vararg blocks: Block) {
		for (block in blocks) {
			exec {
				cubeAll(block.registryName!!.path, modLocation("block/decorative/${block.registryName!!.path}")).renderType("cutout_mipped")
			}
		}
	}
	fun decorativeCubeAll(subdir: String, vararg blocks: Block) {
		for (block in blocks) {
			exec {
				cubeAll(block.registryName!!.path, modLocation("block/decorative/${subdir}/${block.registryName!!.path}"))
			}
		}
	}

	fun decorativeCubeAll(subdir: String, suffix: String, vararg blocks: Block) {
		for (block in blocks) {
			exec {
				cubeAll(block.registryName!!.path, modLocation("block/decorative/${subdir}/${block.registryName!!.path}$suffix"))
			}
		}
	}

	fun decorativeCubeAll(blocks: Collection<Block>) {
		for (block in blocks) {
			exec {
				cubeAll(block.registryName!!.path, modLocation("block/decorative/${block.registryName!!.path}"))
			}
		}
	}

	fun decorativeCubeAll(block: Block, texture: String) {
		exec {
			cubeAll(block.registryName!!.path, modLocation("block/decorative/$texture"))
		}
	}

	fun column(block: Block, side: String, end: String) {
		exec {
			cubeColumn(block.registryName!!.path, modLocation(side), modLocation(end))
		}
	}

	fun orientable(block: Block, side: String, front: String) {
		exec {
			orientable(block.registryName!!.path, modLocation(side), modLocation(front), modLocation(side))
		}
	}

	fun decorativeColumn(it: Block, side: String, end: String) {
		column(it, "block/decorative/$side", "block/decorative/$end")
	}

	fun resourceCubeAll(vararg blocks: Block) {
		for (block in blocks) {
			exec {
				cubeAll(block.registryName!!.path, modLocation("block/resource/${block.registryName!!.path}"))
			}
		}
	}

	fun colored(modelName: String, suffix: String, textureKeys: Map<String, String>) {
		for (color in DyeColor.entries) {
			exec {
				val model = withExistingParent(modelName + "_${color.name.lowercase()}$suffix", modLocation(modelName + suffix))

				for ((key, value) in textureKeys) {
					model.texture(key, modLocation("block/$value/${color.name.lowercase()}"))
				}
			}
		}
	}

	fun colored(blocks: Map<DyeColor?, Block>, textureKeys: Collection<String>) {
		val base = blocks[null]!!.registryName!!.path
		colored(base, textureKeys.associateWith { base })
	}

	fun colored(modelName: String, textureKeys: Map<String, String>) {
		return colored(modelName, "", textureKeys)
	}

	fun colored(modelName: String, textureKeys: Collection<String>, textureName: String) {
		return colored(modelName, "", textureKeys.associateWith { textureName })
	}

	fun colored(modelName: String, textureKeys: Collection<String>) {
		return colored(modelName, "", textureKeys.associateWith { modelName })
	}

	fun colored(modelName: String, suffix: String, textureKeys: Collection<String>) {
		return colored(modelName, suffix, textureKeys.associateWith { modelName })
	}

	fun coloredMachineCombined(modelName: String, textureName: String, textureKeys: Collection<String>) {
		for (state in listOf("_idle", "_error", "_working")) {
			colored(modelName, state, textureKeys.associateWith { textureName })
		}
	}

	fun coloredMachineCombined(modelName: String, textureKeys: Collection<String>) {
		for (state in listOf("_idle", "_error", "_working")) {
			colored(modelName, state, textureKeys.associateWith { modelName })
		}
	}

	fun cable(modelName: String, textureName: String, thin: Boolean = false, powered: Boolean = false) {
		val baseName = if (thin) "base_cable_thin" else "base_cable"

		exec {
			withExistingParent("block/${modelName}_core", modLocation("block/${baseName}_core"))
				.texture("0", textureName)

			withExistingParent("block/${modelName}_connection", modLocation("block/${baseName}_connection"))
				.texture("0", textureName)

			withExistingParent("item/${modelName}", modLocation("item/${baseName}"))
				.texture("0", textureName)
		}

		if (powered && !thin) {
			exec {
				withExistingParent("block/${modelName}_core_powered", modLocation("block/${baseName}_core_powered"))
					.texture("0", textureName)

				withExistingParent("block/${modelName}_connection_powered", modLocation("block/${baseName}_connection_powered"))
					.texture("0", textureName)
			}
		}
	}
}
