package ru.dbotthepony.mc.otm.registry.game

import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.core.registries.Registries
import net.minecraft.world.item.CreativeModeTab
import net.minecraft.world.item.CreativeModeTabs
import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.material.Fluids
import net.neoforged.bus.api.IEventBus
import net.neoforged.neoforge.capabilities.Capabilities
import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent
import net.neoforged.neoforge.fluids.FluidStack
import net.neoforged.neoforge.fluids.capability.IFluidHandler
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.matteryEnergy
import ru.dbotthepony.mc.otm.core.ResourceLocation
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.core.util.CreativeMenuItemComparator
import ru.dbotthepony.mc.otm.registry.MDeferredRegister
import ru.dbotthepony.mc.otm.registry.MRegistry
import ru.dbotthepony.mc.otm.registry.game.MItems.BATTERY_CREATIVE

private fun CreativeModeTab.Output.accept(values: Collection<Item>) {
	for (item in values) {
		accept(item)
	}
}

private fun CreativeModeTab.Output.base(values: Map<DyeColor?, Item>) {
	accept(values[null]!!)
}

private val colorOrder = listOf(
	null,
	DyeColor.WHITE,
	DyeColor.ORANGE,
	DyeColor.MAGENTA,
	DyeColor.LIGHT_BLUE,
	DyeColor.YELLOW,
	DyeColor.LIME,
	DyeColor.PINK,
	DyeColor.GRAY,
	DyeColor.LIGHT_GRAY,
	DyeColor.CYAN,
	DyeColor.PURPLE,
	DyeColor.BLUE,
	DyeColor.BROWN,
	DyeColor.GREEN,
	DyeColor.RED,
	DyeColor.BLACK,
)

private fun CreativeModeTab.Output.colored(values: Map<out DyeColor?, Item>) {
	accept(values[DyeColor.WHITE]!!)
	accept(values[DyeColor.ORANGE]!!)
	accept(values[DyeColor.MAGENTA]!!)
	accept(values[DyeColor.LIGHT_BLUE]!!)
	accept(values[DyeColor.YELLOW]!!)
	accept(values[DyeColor.LIME]!!)
	accept(values[DyeColor.PINK]!!)
	accept(values[DyeColor.GRAY]!!)
	accept(values[DyeColor.LIGHT_GRAY]!!)
	accept(values[DyeColor.CYAN]!!)
	accept(values[DyeColor.PURPLE]!!)
	accept(values[DyeColor.BLUE]!!)
	accept(values[DyeColor.BROWN]!!)
	accept(values[DyeColor.GREEN]!!)
	accept(values[DyeColor.RED]!!)
	accept(values[DyeColor.BLACK]!!)
}

private fun CreativeModeTab.Output.all(values: Map<DyeColor?, Item>) {
	base(values)
	colored(values)
}

private fun CreativeModeTab.Output.energized(value: Item) {
	val empty = ItemStack(value, 1)
	accept(empty)

	val full = empty.copy()
	val energy = full.matteryEnergy ?: throw IllegalArgumentException("${value.registryName} does not implement mattery energy capability")
	energy.fillBattery()

	// FIXME
	if (ItemStack(value, 1).matteryEnergy!!.batteryLevel != energy.batteryLevel && !ItemStack.isSameItemSameComponents(empty, full))
		accept(full)
}

private fun CreativeModeTab.Output.energized(values: Iterable<Item>) {
	for (value in values) {
		energized(value)
	}
}

private fun CreativeModeTab.Output.mattery(value: Item) {
	val empty = ItemStack(value, 1)
	accept(empty)

	val full = empty.copy()
	val matter = full.getCapability(MatteryCapability.MATTER_ITEM) ?: throw IllegalArgumentException("${value.registryName} does not implement matter capability")

	matter.fillMatter()

	// FIXME
	if (ItemStack(value, 1).getCapability(MatteryCapability.MATTER_ITEM)!!.storedMatter != matter.storedMatter && !ItemStack.isSameItemSameComponents(empty, full))
		accept(full)
}

private fun CreativeModeTab.Output.mattery(values: Iterable<Item>) {
	for (value in values) {
		mattery(value)
	}
}

private fun CreativeModeTab.Output.fluids(value: Item) {
	accept(value)

	for (fluid in BuiltInRegistries.FLUID) {
		if (fluid != Fluids.EMPTY && fluid.isSource(fluid.defaultFluidState())) {
			accept(ItemStack(value, 1).also {
				it.getCapability(Capabilities.FluidHandler.ITEM)?.let {
					it.fill(FluidStack(fluid, it.getTankCapacity(0)), IFluidHandler.FluidAction.EXECUTE)
				}
			})
		}
	}
}

private fun addMainCreativeTabItems(consumer: CreativeModeTab.Output) {
	with(consumer) {
		accept(MItems.ENERGY_CABLES.values)

		// machines
		accept(MItems.TWIN_PLATE_PRESS.values)
		accept(MItems.POWERED_FURNACE.values)
		accept(MItems.POWERED_BLAST_FURNACE.values)
		accept(MItems.POWERED_SMOKER.values)

		accept(MItems.ANDROID_STATION.values)
		accept(MItems.ANDROID_CHARGER.values)
		accept(MItems.BATTERY_BANK.values)
		accept(MItems.ENERGY_COUNTER.values)
		accept(MItems.CHEMICAL_GENERATOR.values)
		accept(MItems.ENERGY_SERVO.values)

		accept(MItems.PHANTOM_ATTRACTOR)
		accept(MItems.PAINTER)
		accept(MItems.COBBLESTONE_GENERATOR.values)
		accept(MItems.ESSENCE_STORAGE.values)

		accept(MItems.MATTER_DECOMPOSER.values)
		accept(MItems.MATTER_CAPACITOR_BANK.values)
		accept(MItems.MATTER_CABLE)
		accept(MItems.PATTERN_STORAGE)
		accept(MItems.MATTER_SCANNER.values)
		accept(MItems.MATTER_PANEL.values)
		accept(MItems.MATTER_REPLICATOR.values)
		accept(MItems.MATTER_BOTTLER.values)
		accept(MItems.MATTER_ENTANGLER)
		accept(MItems.MATTER_RECYCLER.values)
		accept(MItems.MATTER_RECONSTRUCTOR.values)

		accept(MItems.GRAVITATION_STABILIZER)

		// storage
		accept(MItems.STORAGE_BUS)
		accept(MItems.STORAGE_IMPORTER)
		accept(MItems.STORAGE_EXPORTER)
		accept(MItems.DRIVE_VIEWER.values)
		accept(MItems.DRIVE_RACK)
		accept(MItems.ITEM_MONITOR.values)
		accept(MItems.STORAGE_CABLE)
		accept(MItems.STORAGE_POWER_SUPPLIER.values)

		// multiblock parts
		accept(MItems.FLYWHEEL_BATTERY)
		accept(MItems.FLYWHEEL_HOUSING)
		accept(MItems.FLYWHEEL_SHAFT)
		accept(MItems.FLYWHEEL_BEARING)

		accept(MItems.GENERATOR_BLOCK)
		accept(MItems.MODULAR_FRAME)
		accept(MItems.HEAVY_MODULAR_FRAME)

		accept(MItems.TRITANIUM_HULL)
		accept(MItems.BLACK_HOLE_GENERATOR)
		accept(MItems.MATTER_INJECTOR)
		accept(MItems.ANTIMATTER_INJECTOR)
		accept(MItems.HIGH_ENERGY_PARTICLE_COLLECTOR)

		accept(MItems.ITEM_INPUT_HATCH)
		accept(MItems.ITEM_OUTPUT_HATCH)
		accept(MItems.ENERGY_INPUT_HATCH)
		accept(MItems.ENERGY_OUTPUT_HATCH)
		accept(MItems.ENERGY_INPUT_INTERFACE)
		accept(MItems.ENERGY_OUTPUT_INTERFACE)
		accept(MItems.MATTER_INPUT_HATCH)
		accept(MItems.MATTER_OUTPUT_HATCH)

		// upgrades
		accept(MItems.MachineUpgrades.Basic.LIST)
		accept(MItems.MachineUpgrades.Normal.LIST)
		accept(MItems.MachineUpgrades.Advanced.LIST)
		accept(MItems.MachineUpgrades.Creative.LIST)

		// misc
		accept(MRegistry.CARGO_CRATES.item)
		accept(MItems.DEV_CHEST)
		accept(MItems.HOLO_SIGN)

		base(MItems.TRITANIUM_DOOR)
		base(MItems.TRITANIUM_TRAPDOOR)
		accept(MRegistry.TRITANIUM_PRESSURE_PLATE.item)
		accept(MItems.TRITANIUM_ANVIL[null]!![0])

		accept(MItems.GRILL.values)

		// accept(MItems.MATTER_DUST)

		accept(MItems.TRITANIUM_ORE)
		accept(MItems.DEEPSLATE_TRITANIUM_ORE)
		accept(MItems.TRITANIUM_ORE_CLUMP)
		accept(MItems.TRITANIUM_RAW_BLOCK)
		accept(MItems.TRITANIUM_DUST)
		accept(MItems.TRITANIUM_NUGGET)
		accept(MItems.TRITANIUM_INGOT)
		accept(MItems.TRITANIUM_INGOT_BLOCK)

		accept(MItems.DILITHIUM_ORE)
		accept(MItems.DEEPSLATE_DILITHIUM_ORE)
		accept(MItems.DILITHIUM_CRYSTAL)
		accept(MItems.DILITHIUM_CRYSTAL_BLOCK)

		accept(MItems.WITHERED_STEEL)
		accept(MItems.WITHERED_STEEL_BLOCK)

		accept(MItems.ROFLITE_ALLOY_INGOT)
		accept(MItems.ROFLITE_ALLOY_BLOCK)

		accept(MItems.TRITANIUM_TOOLS)
		accept(MItems.TRITANIUM_SHIELD)
		accept(MItems.SIMPLE_TRITANIUM_ARMOR)
		accept(MItems.TRITANIUM_ARMOR)

		accept(MItems.WITHERED_STEEL_SWORD)

		energized(MItems.ENERGY_SWORD)

		accept(MItems.REDSTONE_INTERACTOR)
		accept(MItems.EXPLOSIVE_HAMMER)
		accept(ItemStack(MItems.EXPLOSIVE_HAMMER).also { MItems.EXPLOSIVE_HAMMER.prime(it) })

		accept(MItems.BLACK_HOLE_SCANNER)
		accept(MItems.GRAVITATION_FIELD_LIMITER)
		accept(MItems.GRAVITATION_FIELD_SENSOR)
		accept(MItems.PORTABLE_GRAVITATION_STABILIZER)
		accept(MItems.BLACK_HOLE)
		accept(MItems.GRAVITATIONAL_DISRUPTOR)

		accept(MItems.CHEST_UPGRADER)
		accept(MItems.CONFIGURATOR)

		accept(MItems.ESSENCE_SERVO)

		energized(MItems.ALL_BATTERIES)
		mattery(MItems.MATTER_CAPACITORS)
		accept(MItems.PATTERN_DRIVE_NORMAL)
		accept(MItems.PATTERN_DRIVE_DOUBLE)
		accept(MItems.PATTERN_DRIVE_TRIPLE)
		accept(MItems.PATTERN_DRIVE_QUAD)
		accept(MItems.PATTERN_DRIVE_CREATIVE)
		accept(MItems.PATTERN_DRIVE_CREATIVE2)

		accept(MItems.PORTABLE_CONDENSATION_DRIVE)
		accept(MItems.PORTABLE_DENSE_CONDENSATION_DRIVE)

		fluids(MItems.FLUID_CAPSULE)
		fluids(MItems.FLUID_TANK)
		accept(MItems.INFINITE_WATER_SOURCE)

		base(MItems.CARGO_CRATE_MINECARTS)

		accept(MItems.NUTRIENT_PASTE)
		accept(MItems.IMPERFECT_BREAD)
		accept(ItemStack(MItems.IMPERFECT_BREAD).also {
			it[MDataComponentTypes.INERT] = true
		})

		// exo
		accept(MItems.EXOPACK_PROBE)
		accept(MItems.ExopackUpgrades.INVENTORY_UPGRADE_CREATIVE)
		accept(MItems.ExopackUpgrades.CRAFTING_UPGRADE)
		accept(MItems.ExopackUpgrades.SMELTING_UPGRADE)
		accept(MItems.ExopackUpgrades.ENDER_UPGRADE)

		accept(MItems.ExopackUpgrades.INVENTORY_UPGRADE_BIG)
		accept(MItems.ExopackUpgrades.INVENTORY_UPGRADE_HUGE)
		accept(MItems.ExopackUpgrades.INVENTORY_UPGRADE_WITHER)
		accept(MItems.ExopackUpgrades.INVENTORY_UPGRADE_ENDER_DRAGON)

		accept(MItems.ExopackUpgrades.INVENTORY_UPGRADES)
		// /exo

		accept(MItems.PILLS)

		accept(MItems.COMPONENTS)
	}
}

private fun addDecorativeTabItems(consumer: CreativeModeTab.Output) {
	with(consumer) {
		accept(MItems.REDSTONE_LAMP_INVERTED)
		accept(MItems.REINFORCED_REDSTONE_LAMP)
		accept(MItems.REINFORCED_REDSTONE_LAMP_INVERTED)
		accept(MItems.LABORATORY_LAMP)
		accept(MItems.LABORATORY_LAMP_INVERTED)

		accept(MItems.DANGER_STRIPE_BLOCK)
		accept(MItems.METAL_BEAM)
		accept(MItems.METAL_BEAM_CENTER)
		accept(MItems.ENGINE)

		accept(MItems.TRITANIUM_STRIPED_BLOCK.values)
		accept(MItems.TRITANIUM_STRIPED_STAIRS.values)
		accept(MItems.TRITANIUM_STRIPED_SLAB.values)
		accept(MItems.TRITANIUM_STRIPED_WALL.values)
		accept(MItems.CARBON_FIBRE_BLOCK)
		accept(MItems.METAL_JUNK)
		accept(MItems.METAL_MESH)

		accept(MItems.TRITANIUM_BARS)
		accept(MItems.METAL_RAILING)

		colored(MItems.TRITANIUM_DOOR)
		colored(MItems.TRITANIUM_TRAPDOOR)
		accept(MRegistry.TRITANIUM_PRESSURE_PLATE.items.values)

		accept(MItems.TRITANIUM_ANVIL[null]!!)
		colored(MRegistry.CARGO_CRATES.items)

		colored(MItems.CARGO_CRATE_MINECARTS)

		all(MRegistry.COMPUTER_TERMINAL.allItems)
		all(MRegistry.STAR_CHAIR.allItems)

		all(MRegistry.DECORATIVE_CRATE.allItems)

		for (color in colorOrder) {
			accept(MRegistry.TRITANIUM_BLOCK.allItems[color]!!)
			accept(MRegistry.TRITANIUM_STAIRS.allItems[color]!!)
			accept(MRegistry.TRITANIUM_SLAB.allItems[color]!!)
			accept(MRegistry.TRITANIUM_WALL.allItems[color]!!)
		}

		all(MRegistry.INDUSTRIAL_GLASS.allItems)
		all(MRegistry.INDUSTRIAL_GLASS_PANE.allItems)

		colored(MRegistry.UNREFINED_FLOOR_TILES.items)
		colored(MRegistry.FLOOR_TILES.items)
		colored(MRegistry.FLOOR_TILES_STAIRS.items)
		colored(MRegistry.FLOOR_TILES_SLAB.items)

		all(MRegistry.VENT.allItems)
		all(MRegistry.VENT_ALTERNATIVE.allItems)

		accept(MRegistry.TRITANIUM_STRIPED_BLOCK.flatItems)
		accept(MRegistry.TRITANIUM_STRIPED_STAIRS.flatItems)
		accept(MRegistry.TRITANIUM_STRIPED_SLAB.flatItems)
		accept(MRegistry.TRITANIUM_STRIPED_WALL.flatItems)
	}
}

object MCreativeTabs {
	private val registry = MDeferredRegister(Registries.CREATIVE_MODE_TAB)

	val MAIN: CreativeModeTab by registry.register("main") {
		CreativeModeTab.builder()
			.title(TranslatableComponent("itemGroup.otm"))
			.icon { ItemStack(BATTERY_CREATIVE, 1) }
			.withTabsBefore(CreativeModeTabs.SPAWN_EGGS)
			.build()
	}

	val DECORATIVE: CreativeModeTab by registry.register("decorative") {
		CreativeModeTab.builder()
			.title(TranslatableComponent("itemGroup.otm_decorative"))
			.icon { ItemStack(MRegistry.VENT.item, 1) }
			.withTabsBefore(ResourceLocation(OverdriveThatMatters.MOD_ID, "main"))
			.build()
	}

	fun initialize(bus: IEventBus) {
		registry.register(bus)
	}

	fun register(event: BuildCreativeModeTabContentsEvent) {
		CreativeMenuItemComparator.invalidate()

		when (event.tab) {
			MAIN -> addMainCreativeTabItems(event)
			DECORATIVE -> addDecorativeTabItems(event)
		}
	}
}
