package ru.dbotthepony.mc.otm.datagen.items

import net.minecraft.data.models.ItemModelGenerators
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.packs.PackType
import net.minecraft.world.item.ArmorItem
import net.minecraft.world.item.Item
import net.minecraftforge.client.model.generators.ItemModelProvider
import net.minecraftforge.client.model.generators.ModelBuilder
import net.minecraftforge.data.event.GatherDataEvent
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.datagen.DataGen
import ru.dbotthepony.mc.otm.datagen.modLocation
import java.util.LinkedList

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

	fun exec(func: () -> Unit): MatteryItemModelProvider {
		callbacks.add(func)
		return this
	}

	override fun registerModels() {
		for (callback in callbacks) {
			callback.invoke()
		}
	}

	fun block(item: Item) = exec { withExistingParent(item.registryName!!.path, modLocation("block/${item.registryName!!.path}")) }
	fun block(item: Item, path: String) = exec { withExistingParent(item.registryName!!.path, modLocation("block/$path")) }
	fun blocks(vararg items: Item) = items.forEach(this::block)
	fun blocks(items: Collection<Item>) = items.forEach(this::block)

	fun generated(item: Item, texture: ResourceLocation) = exec {
		withExistingParent(item.registryName!!.path, GENERATED).texture("layer0", texture)
	}

	fun generatedTranslucent(item: Item, texture: ResourceLocation) = exec {
		withExistingParent(item.registryName!!.path, GENERATED).texture("layer0", texture).renderType("translucent")
	}

	fun handheld(item: Item, texture: ResourceLocation) = exec {
		withExistingParent(item.registryName!!.path, HANDHELD).texture("layer0", texture)
	}

	fun generated(item: Item) = generated(item, modLocation("item/${item.registryName!!.path}"))
	fun generated(vararg items: Item) = items.forEach { generated(it, modLocation("item/${it.registryName!!.path}")) }
	fun KOT(vararg items: Item) = items.forEach { generated(it, modLocation("block/ph_kitty")) }
	fun generated(items: Collection<Item>) = items.forEach { generated(it, modLocation("item/${it.registryName!!.path}")) }
	fun generatedBlock(vararg items: Item) = items.forEach { generated(it, modLocation("block/${it.registryName!!.path}")) }
	fun generatedBlockDecorative(vararg items: Item) = items.forEach { generated(it, modLocation("block/decorative/${it.registryName!!.path}")) }
	fun handheld(vararg items: Item) = items.forEach { handheld(it, modLocation("item/${it.registryName!!.path}")) }
	fun handheld(items: Collection<Item>) = items.forEach { handheld(it, modLocation("item/${it.registryName!!.path}")) }

	fun generated(item: Item, prefix: String) = generated(item, modLocation("item/${prefix}${item.registryName!!.path}"))
	fun generatedStrict(item: Item, path: String) = generated(item, modLocation("item/$path"))
	fun handheld(item: Item, prefix: String) = handheld(item, modLocation("item/${prefix}${item.registryName!!.path}"))

	fun component(item: Item) = generated(item, "component/")
	fun components(vararg items: Item) = items.forEach(this::component)
	fun components(items: Collection<Item>) = items.forEach(this::component)
	fun resource(item: Item) = generated(item, "resources/")
	fun resources(vararg items: Item) = items.forEach(this::resource)

	fun generatedTiered(items: Array<out Item>, prefix: String) {
		var i = 0

		for (item in items) {
			generated(item, modLocation("item/$prefix$i"))
			i++
		}
	}

	fun generatedTiered(items: Collection<Item>, prefix: String) {
		var i = 0

		for (item in items) {
			generated(item, modLocation("item/$prefix$i"))
			i++
		}
	}

	fun armorWithTrims(item: Item, texture: ResourceLocation) = exec {
		val mainModel = withExistingParent(item.registryName!!.path, GENERATED).texture("layer0", texture)

		if (item is ArmorItem) {
			for ((i, material) in ARMOR_TRIM_MATERIALS.withIndex()) {
				val trimLocation = ResourceLocation("trims/items/${item.type.getName()}_trim_${material}")
				existingFileHelper.trackGenerated(trimLocation, PackType.CLIENT_RESOURCES, ".png", "textures")

				val overrideModel = withExistingParent("${item.registryName!!.path}_${material}_trim", GENERATED)
					.texture("layer0", texture)
					.texture("layer1", trimLocation)

				mainModel.override()
					.predicate(ItemModelGenerators.TRIM_TYPE_PREDICATE_ID, (i + 1).toFloat() / ARMOR_TRIM_MATERIALS.size.toFloat())
					.model(overrideModel)
					.end()
			}
		}
	}

	fun armorWithTrims(vararg items: Item) = items.forEach { armorWithTrims(it, modLocation("item/${it.registryName!!.path}")) }
	fun armorWithTrims(items: Collection<Item>) = items.forEach { armorWithTrims(it, modLocation("item/${it.registryName!!.path}")) }

	fun armorColored(item: Item) = exec {
		withExistingParent(item.registryName!!.path, GENERATED)
			.texture("layer0", modLocation("item/${item.registryName!!.path}_base"))
			.texture("layer1", modLocation("item/${item.registryName!!.path}_overlay"))
	}
	fun armorColored(vararg items: Item) = items.forEach { armorColored(it) }
	fun armorColored(items: Collection<Item>) = items.forEach { armorColored(it) }

	fun upgrade(item: Item, upgradeType: String, tier: String = "tier0") = exec {
		withExistingParent(item.registryName!!.path, GENERATED)
			.texture("layer0", modLocation("item/machine_upgrade_$tier"))
			.texture("layer1", modLocation("item/machine_upgrade_icon_$upgradeType"))
	}

	companion object {
		val ARMOR_TRIM_MATERIALS = listOf("quartz", "iron", "netherite", "redstone", "copper", "gold", "emerald", "diamond", "lapis", "amethyst")
		val GENERATED = ResourceLocation("minecraft", "item/generated")
		val HANDHELD = ResourceLocation("minecraft", "item/handheld")
		private val LOGGER = LogManager.getLogger()
	}
}
