package ru.dbotthepony.mc.otm.compat.jei

import mezz.jei.api.IModPlugin
import mezz.jei.api.JeiPlugin
import mezz.jei.api.constants.RecipeTypes
import mezz.jei.api.constants.VanillaTypes
import mezz.jei.api.gui.handlers.IGuiContainerHandler
import mezz.jei.api.helpers.IJeiHelpers
import mezz.jei.api.neoforge.NeoForgeTypes
import mezz.jei.api.registration.IGuiHandlerRegistration
import mezz.jei.api.registration.IModInfoRegistration
import mezz.jei.api.registration.IRecipeCatalystRegistration
import mezz.jei.api.registration.IRecipeCategoryRegistration
import mezz.jei.api.registration.IRecipeRegistration
import mezz.jei.api.registration.IRecipeTransferRegistration
import mezz.jei.api.runtime.IClickableIngredient
import mezz.jei.api.runtime.IJeiRuntime
import net.minecraft.client.renderer.Rect2i
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
import ru.dbotthepony.mc.otm.client.screen.widget.FluidGaugePanel
import ru.dbotthepony.mc.otm.core.ResourceLocation
import ru.dbotthepony.mc.otm.core.collect.filter
import ru.dbotthepony.mc.otm.core.collect.filterIsInstance
import ru.dbotthepony.mc.otm.core.collect.map
import ru.dbotthepony.mc.otm.core.collect.toList
import ru.dbotthepony.mc.otm.menu.decorative.PainterMenu
import ru.dbotthepony.mc.otm.menu.matter.MatterEntanglerMenu
import ru.dbotthepony.mc.otm.menu.tech.PlatePressMenu
import ru.dbotthepony.mc.otm.menu.tech.PoweredFurnaceMenu
import ru.dbotthepony.mc.otm.recipe.PainterRecipe
import ru.dbotthepony.mc.otm.registry.game.MItems
import ru.dbotthepony.mc.otm.registry.game.MRecipes
import java.util.*
import java.util.stream.Collectors
import kotlin.properties.Delegates

var isJeiLoaded = false
	private set

@JeiPlugin
@Suppress("unused")
class JEIPlugin : IModPlugin {
	companion object {
		private val LOCATION = ResourceLocation(OverdriveThatMatters.MOD_ID, "jei_plugin")

		var helpers: IJeiHelpers by Delegates.notNull()
			private set

		private var _RUNTIME: IJeiRuntime? = null

		val RUNTIME: IJeiRuntime
			get() = checkNotNull(_RUNTIME) { "JEI runtime is unavailable" }
	}

	init {
		isJeiLoaded = true
	}

	override fun getPluginUid(): ResourceLocation {
		return LOCATION
	}

	override fun registerModInfo(modAliasRegistration: IModInfoRegistration) {
		modAliasRegistration.addModAliases(OverdriveThatMatters.MOD_ID, "otm", "matteroverdrive")
	}

	override fun registerRecipeCatalysts(registration: IRecipeCatalystRegistration) {
		registration.addRecipeCatalyst(ItemStack(MItems.CHEMICAL_GENERATOR[null]!!), RecipeTypes.FUELING)
		registration.addRecipeCatalyst(ItemStack(MItems.POWERED_FURNACE[null]!!), RecipeTypes.SMELTING)
		registration.addRecipeCatalyst(ItemStack(MItems.ExopackUpgrades.SMELTING_UPGRADE), RecipeTypes.SMELTING)
		registration.addRecipeCatalyst(ItemStack(MItems.POWERED_BLAST_FURNACE[null]!!), RecipeTypes.BLASTING)
		registration.addRecipeCatalyst(ItemStack(MItems.POWERED_SMOKER[null]!!), RecipeTypes.SMOKING)
		registration.addRecipeCatalyst(ItemStack(MItems.GRILL[null]!!), RecipeTypes.SMOKING)
		MItems.POWERED_SMOKER.values.forEach { registration.addRecipeCatalyst(ItemStack(it), MicrowaveRecipeCategory.recipeType) }
		registration.addRecipeCatalyst(ItemStack(MItems.ExopackUpgrades.CRAFTING_UPGRADE), RecipeTypes.CRAFTING)
		registration.addRecipeCatalyst(ItemStack(MItems.ITEM_MONITOR[null]!!), RecipeTypes.CRAFTING)
		MItems.TWIN_PLATE_PRESS.values.forEach { registration.addRecipeCatalyst(ItemStack(it), PlatePressRecipeCategory.recipeType) }
		registration.addRecipeCatalyst(ItemStack(MItems.PAINTER), PainterRecipeCategory.recipeType)
		registration.addRecipeCatalyst(ItemStack(MItems.MATTER_ENTANGLER), MatterEntanglerRecipeCategory.recipeType)
	}

	override fun onRuntimeAvailable(jeiRuntime: IJeiRuntime) {
		_RUNTIME = jeiRuntime
	}

	override fun onRuntimeUnavailable() {
		_RUNTIME = null
	}

	override fun registerCategories(registration: IRecipeCategoryRegistration) {
		helpers = registration.jeiHelpers
		registration.addRecipeCategories(PlatePressRecipeCategory)
		registration.addRecipeCategories(PainterRecipeCategory)
		registration.addRecipeCategories(MatterEntanglerRecipeCategory)
		registration.addRecipeCategories(MicrowaveRecipeCategory)
	}

	override fun registerRecipes(registration: IRecipeRegistration) {
		val level = minecraft.level ?: throw NullPointerException("No ClientLevel. OLOLOLOLOLOLO")

		registration.addRecipes(PlatePressRecipeCategory.recipeType, level.recipeManager.getAllRecipesFor(MRecipes.PLATE_PRESS).filter { !it.value.isIncomplete }.map { it.value })
		registration.addRecipes(PainterRecipeCategory.recipeType, level.recipeManager.getAllRecipesFor(MRecipes.PAINTER).iterator().filter { !it.value.isIncomplete }.map { it.value }.filterIsInstance<PainterRecipe>().toList())
		registration.addRecipes(MatterEntanglerRecipeCategory.recipeType, level.recipeManager.getAllRecipesFor(MRecipes.MATTER_ENTANGLER).filter { !it.value.isIncomplete }.map { it.value })
		registration.addRecipes(MicrowaveRecipeCategory.recipeType, level.recipeManager.getAllRecipesFor(MRecipes.MICROWAVE).filter { !it.value.isIncomplete }.map { it.value })
	}

	override fun registerRecipeTransferHandlers(registration: IRecipeTransferRegistration) {
		val helper = registration.transferHelper

		registration.addRecipeTransferHandler(ExopackInventoryTransferHandler(helper), RecipeTypes.CRAFTING)
		registration.addRecipeTransferHandler(simpleTransferInfo(MatterEntanglerRecipeCategory.recipeType, MatterEntanglerMenu::inputs))
		registration.addRecipeTransferHandler(simpleTransferInfo0(PainterRecipeCategory.recipeType, PainterMenu::inputSlot))
		registration.addRecipeTransferHandler(simpleTransferInfo(PlatePressRecipeCategory.recipeType, PlatePressMenu::inputSlots))
		registration.addRecipeTransferHandler(simpleTransferInfo(MicrowaveRecipeCategory.recipeType, PoweredFurnaceMenu::inputSlots))
	}

	override fun registerGuiHandlers(registration: IGuiHandlerRegistration) {
		registration.addGenericGuiContainerHandler(MatteryScreen::class.java, object : IGuiContainerHandler<MatteryScreen<*>> {
			override fun getGuiExtraAreas(containerScreen: MatteryScreen<*>): MutableList<Rect2i> {
				return containerScreen.panelsView.stream()
					.map {
						it.performLayoutIfNeeded()
						it.updateAbsoluteCoordinates()
						it.calculateAbsoluteObstructingRectangles()
					}
					.flatMap { it.stream() }
					.map { it.toIntRect() }
					.collect(Collectors.toList())
			}

			override fun getClickableIngredientUnderMouse(
				containerScreen: MatteryScreen<*>,
				mouseX: Double,
				mouseY: Double
			): Optional<IClickableIngredient<*>> {
				return Panel2ClickableIngredient.find(mouseX, mouseY, VanillaTypes.ITEM_STACK, containerScreen.panelsView, AbstractSlotPanel<*>::itemStack).or {
					Panel2ClickableIngredient.find(mouseX, mouseY, NeoForgeTypes.FLUID_STACK, containerScreen.panelsView) { it: FluidGaugePanel<*> -> it.widget.fluid }
				}
			}
		})
	}
}
