package ru.dbotthepony.mc.otm

import net.minecraft.resources.ResourceLocation
import net.neoforged.api.distmarker.Dist
import net.neoforged.bus.api.EventPriority
import net.neoforged.fml.common.Mod
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent
import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent
import ru.dbotthepony.mc.otm.android.AndroidResearchDescription
import ru.dbotthepony.mc.otm.android.AndroidResearchDescriptions
import ru.dbotthepony.mc.otm.android.AndroidResearchManager
import ru.dbotthepony.mc.otm.android.AndroidResearchResult
import ru.dbotthepony.mc.otm.android.AndroidResearchResults
import ru.dbotthepony.mc.otm.android.feature.EnderTeleporterFeature
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
import ru.dbotthepony.mc.otm.block.entity.decorative.DevChestBlockEntity
import ru.dbotthepony.mc.otm.capability.MatteryPlayer
import ru.dbotthepony.mc.otm.capability.drive.DrivePool
import ru.dbotthepony.mc.otm.client.AndroidAbilityKeyMapping
import ru.dbotthepony.mc.otm.client.AndroidMenuKeyMapping
import ru.dbotthepony.mc.otm.client.MatteryGUI
import ru.dbotthepony.mc.otm.client.MatteryTooltipComponents
import ru.dbotthepony.mc.otm.client.createCursors
import ru.dbotthepony.mc.otm.client.model.ExosuitModel
import ru.dbotthepony.mc.otm.client.model.GravitationStabilizerModel
import ru.dbotthepony.mc.otm.client.model.TritaniumArmorModel
import ru.dbotthepony.mc.otm.client.model.entity.BreadMonsterModel
import ru.dbotthepony.mc.otm.client.onMovementInputUpdate
import ru.dbotthepony.mc.otm.client.onScreenOpen
import ru.dbotthepony.mc.otm.client.onPostScreenInit
import ru.dbotthepony.mc.otm.client.onMouseDragged
import ru.dbotthepony.mc.otm.client.onMouseScrolled
import ru.dbotthepony.mc.otm.client.onClientTickPre
import ru.dbotthepony.mc.otm.client.onClientTickPost
import ru.dbotthepony.mc.otm.client.onClientConnected
import ru.dbotthepony.mc.otm.client.onClientDisconnected
import ru.dbotthepony.mc.otm.client.onClientPostRender
import ru.dbotthepony.mc.otm.client.tooltipEvent
import ru.dbotthepony.mc.otm.client.render.ChartTooltipElement
import ru.dbotthepony.mc.otm.client.render.ShockwaveRenderer
import ru.dbotthepony.mc.otm.client.render.blockentity.BatteryBankRenderer
import ru.dbotthepony.mc.otm.client.render.blockentity.MatterBatteryBankRenderer
import ru.dbotthepony.mc.otm.compat.curios.isCuriosLoaded
import ru.dbotthepony.mc.otm.compat.curios.onCuriosSlotModifiersUpdated
import ru.dbotthepony.mc.otm.compat.vanilla.MatteryChestMenu
import ru.dbotthepony.mc.otm.config.AndroidConfig
import ru.dbotthepony.mc.otm.config.CablesConfig
import ru.dbotthepony.mc.otm.config.ClientConfig
import ru.dbotthepony.mc.otm.config.ExopackConfig
import ru.dbotthepony.mc.otm.config.ItemsConfig
import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.config.ServerConfig
import ru.dbotthepony.mc.otm.config.ToolsConfig
import ru.dbotthepony.mc.otm.data.FlywheelMaterials
import ru.dbotthepony.mc.otm.data.world.DecimalProvider
import ru.dbotthepony.mc.otm.entity.WitheredSkeletonSpawnHandler
import ru.dbotthepony.mc.otm.item.ChestUpgraderItem
import ru.dbotthepony.mc.otm.item.tool.ExplosiveHammerItem
import ru.dbotthepony.mc.otm.item.armor.TritaniumArmorItem
import ru.dbotthepony.mc.otm.item.QuantumBatteryItem
import ru.dbotthepony.mc.otm.item.PortableCondensationDriveItem
import ru.dbotthepony.mc.otm.item.consumables.NotNormalFood
import ru.dbotthepony.mc.otm.item.tool.RedstoneInteractorItem
import ru.dbotthepony.mc.otm.matter.AbstractRegistryAction
import ru.dbotthepony.mc.otm.matter.IMatterFunction
import ru.dbotthepony.mc.otm.matter.MatterManager
import ru.dbotthepony.mc.otm.network.*
import ru.dbotthepony.mc.otm.registry.*
import ru.dbotthepony.mc.otm.registry.game.AndroidFeatures
import ru.dbotthepony.mc.otm.registry.game.MArmorMaterials
import ru.dbotthepony.mc.otm.registry.game.MBlockColors
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
import ru.dbotthepony.mc.otm.registry.game.MBlocks
import ru.dbotthepony.mc.otm.registry.game.MCreativeTabs
import ru.dbotthepony.mc.otm.registry.game.MDataComponentTypes
import ru.dbotthepony.mc.otm.registry.game.MEntityTypes
import ru.dbotthepony.mc.otm.registry.game.MFluids
import ru.dbotthepony.mc.otm.registry.game.MItems
import ru.dbotthepony.mc.otm.registry.game.MMenus
import ru.dbotthepony.mc.otm.registry.game.MRecipes
import ru.dbotthepony.mc.otm.registry.game.MSoundEvents
import ru.dbotthepony.mc.otm.registry.game.MStats
import ru.dbotthepony.mc.otm.registry.data.LootModifiers
import ru.dbotthepony.mc.otm.registry.data.MHeightProviders
import ru.dbotthepony.mc.otm.registry.data.MItemFunctionTypes
import ru.dbotthepony.mc.otm.registry.data.MLootItemConditions
import ru.dbotthepony.mc.otm.registry.data.MLootNumberProviders
import ru.dbotthepony.mc.otm.registry.data.MPlacementModifiers
import ru.dbotthepony.mc.otm.registry.data.MWorldGenFeatures
import ru.dbotthepony.mc.otm.server.MCommands
import ru.dbotthepony.mc.otm.storage.StorageStack
import ru.dbotthepony.mc.otm.triggers.KillAsAndroidTrigger
import thedarkcolour.kotlinforforge.neoforge.forge.DIST
import thedarkcolour.kotlinforforge.neoforge.forge.FORGE_BUS
import thedarkcolour.kotlinforforge.neoforge.forge.LOADING_CONTEXT
import thedarkcolour.kotlinforforge.neoforge.forge.MOD_BUS

@Mod(OverdriveThatMatters.MOD_ID)
object OverdriveThatMatters {
	const val MOD_ID = "overdrive_that_matters"

	@JvmStatic
	fun loc(path: String): ResourceLocation = ResourceLocation.fromNamespaceAndPath(MOD_ID, path)

	init {
		MBlocks.register(MOD_BUS)
		MFluids.register(MOD_BUS)
		MBlockEntities.register(MOD_BUS)
		MEntityTypes.register(MOD_BUS)
		MMenus.register(MOD_BUS)
		MItems.register(MOD_BUS)
		AndroidFeatures.register(MOD_BUS)
		MSoundEvents.register(MOD_BUS)
		LootModifiers.register(MOD_BUS)
		MItemFunctionTypes.register(MOD_BUS)
		MLootItemConditions.register(MOD_BUS)
		MRecipes.register(MOD_BUS)
		MDataComponentTypes.register(MOD_BUS)
		MArmorMaterials.register(MOD_BUS)
		MCriteriaTriggers.register(MOD_BUS)
		MStats.register(MOD_BUS)
		MWorldGenFeatures.register(MOD_BUS)
		CommandArgumentTypes.register(MOD_BUS)
		MHeightProviders.register(MOD_BUS)
		MPlacementModifiers.register(MOD_BUS)
		MLootNumberProviders.register(MOD_BUS)

		StorageStack.register(MOD_BUS)
		MatteryChestMenu.register(MOD_BUS)

		MCreativeTabs.initialize(MOD_BUS)

		MOD_BUS.addListener(::registerNetworkPackets)

		DecimalProvider.register(MOD_BUS)
		AndroidResearchDescription.register(MOD_BUS)
		AndroidResearchDescriptions.register(MOD_BUS)
		AndroidResearchResult.register(MOD_BUS)
		AndroidResearchResults.register(MOD_BUS)

		AbstractRegistryAction.register(MOD_BUS)
		IMatterFunction.register(MOD_BUS)

		MRegistry.initialize(MOD_BUS)
		MatterManager.initialize(MOD_BUS)

		MOD_BUS.addListener(EventPriority.HIGHEST, this::setup)
		MOD_BUS.addListener(EventPriority.NORMAL, this::setupClient)

		if (DIST == Dist.CLIENT) {
			MOD_BUS.addListener(EventPriority.NORMAL, AndroidMenuKeyMapping::register)
			MOD_BUS.addListener(EventPriority.NORMAL, AndroidAbilityKeyMapping::register)
			MOD_BUS.addListener(EventPriority.NORMAL, TritaniumArmorModel::register)
			MOD_BUS.addListener(EventPriority.NORMAL, GravitationStabilizerModel::register)
			MOD_BUS.addListener(EventPriority.NORMAL, BreadMonsterModel::register)
			MOD_BUS.addListener(EventPriority.NORMAL, MCreativeTabs::register)

			MOD_BUS.addListener(EventPriority.NORMAL, BatteryBankRenderer.Companion::onRegisterAdditionalModels)
			MOD_BUS.addListener(EventPriority.NORMAL, MatterBatteryBankRenderer.Companion::onRegisterAdditionalModels)

			MOD_BUS.addListener(EventPriority.NORMAL, ChartTooltipElement.Companion::register)
			MOD_BUS.addListener(EventPriority.NORMAL, MatteryTooltipComponents::registerComponents)

			MOD_BUS.addListener(EventPriority.HIGH, MatteryGUI::registerGuiLayers)

			MBlockColors.register(MOD_BUS)
		}

		val container = LOADING_CONTEXT.activeContainer
		ClientConfig.register(container)
		ServerConfig.register(container)
		CablesConfig.register(container)
		AndroidConfig.register(container)
		ExopackConfig.register(container)
		ItemsConfig.register(container)
		MachinesConfig.register(container)
		ToolsConfig.register(container)
	}

	private fun setup(event: FMLCommonSetupEvent) {
		FORGE_BUS.addListener(EventPriority.NORMAL, DrivePool::onWorldSave)

		FORGE_BUS.addListener(EventPriority.HIGHEST, ::onServerStopped)
		FORGE_BUS.addListener(EventPriority.HIGHEST, ::onServerStopping)
		FORGE_BUS.addListener(EventPriority.HIGHEST, ::onServerStarting)
		FORGE_BUS.addListener(EventPriority.HIGH, ::onLevelTickPre)
		FORGE_BUS.addListener(EventPriority.LOWEST, ::onLevelTickPost)
		FORGE_BUS.addListener(EventPriority.HIGH, ::onServerTickPre)
		FORGE_BUS.addListener(EventPriority.LOWEST, ::onServerTickPost)

		FORGE_BUS.addListener(EventPriority.NORMAL, MatteryPlayer.Companion::onPlayerTickPre)
		FORGE_BUS.addListener(EventPriority.NORMAL, MatteryPlayer.Companion::onPlayerTickPost)
		FORGE_BUS.addListener(EventPriority.NORMAL, MatteryPlayer.Companion::isMobEffectApplicable)
		FORGE_BUS.addListener(EventPriority.LOW, MatteryPlayer.Companion::onHurtEvent)
		FORGE_BUS.addListener(EventPriority.NORMAL, MatteryPlayer.Companion::onPlayerChangeDimensionEvent)
		FORGE_BUS.addListener(EventPriority.LOWEST, MatteryPlayer.Companion::onPlayerDeath)
		FORGE_BUS.addListener(EventPriority.NORMAL, MatteryPlayer.Companion::onPlayerCloneEvent)
		FORGE_BUS.addListener(EventPriority.NORMAL, MatteryPlayer.Companion::onPlayerSpawnPhantoms)
		FORGE_BUS.addListener(EventPriority.NORMAL, MatteryPlayer.Companion::onStartTracking)
		FORGE_BUS.addListener(EventPriority.NORMAL, MatteryPlayer.Companion::onStopTracking)

		FORGE_BUS.addListener(EventPriority.NORMAL, QuantumBatteryItem.Companion::tick)
		FORGE_BUS.addListener(EventPriority.LOWEST, PortableCondensationDriveItem.Companion::onPickupEvent)

		FORGE_BUS.addListener(EventPriority.NORMAL, AndroidResearchManager::reloadEvent)
		FORGE_BUS.addListener(EventPriority.NORMAL, AndroidResearchManager::syncEvent)

		FORGE_BUS.addListener(EventPriority.NORMAL, FlywheelMaterials::reloadEvent)
		FORGE_BUS.addListener(EventPriority.NORMAL, FlywheelMaterials::onDataPackSync)

		FORGE_BUS.addListener(EventPriority.NORMAL, MatterManager::reloadEvent)
		FORGE_BUS.addListener(EventPriority.NORMAL, MatterManager::onServerStarted)
		FORGE_BUS.addListener(EventPriority.NORMAL, MatterManager::onDataPackSync)
		FORGE_BUS.addListener(EventPriority.NORMAL, MatterManager::addCommands)

		FORGE_BUS.addListener(EventPriority.NORMAL, MatteryBlockEntity.Companion::onServerStopping)
		FORGE_BUS.addListener(EventPriority.NORMAL, MatteryBlockEntity.Companion::onLevelUnload)
		FORGE_BUS.addListener(EventPriority.NORMAL, MatteryBlockEntity.Companion::onWatch)
		FORGE_BUS.addListener(EventPriority.NORMAL, MatteryBlockEntity.Companion::onForget)
		FORGE_BUS.addListener(EventPriority.NORMAL, MatteryBlockEntity.Companion::playerDisconnected)
		FORGE_BUS.addListener(EventPriority.NORMAL, MatteryBlockEntity.Companion::postLevelTick)

		FORGE_BUS.addListener(EventPriority.LOWEST, KillAsAndroidTrigger::onKill)

		//fuck if I know
		FORGE_BUS.addListener(EventPriority.NORMAL, WitheredSkeletonSpawnHandler::onEntityJoin)

		FORGE_BUS.addListener(EventPriority.NORMAL, EnderTeleporterFeature.Companion::onEntityDeath)
		FORGE_BUS.addListener(EventPriority.HIGH, TritaniumArmorItem.Companion::onHurt)

		FORGE_BUS.addListener(EventPriority.NORMAL, ExplosiveHammerItem.Companion::onLeftClickBlock)

		FORGE_BUS.addListener(EventPriority.NORMAL, ChestUpgraderItem.Companion::onEntityInteract)

		FORGE_BUS.addListener(EventPriority.NORMAL, DevChestBlockEntity.Companion::mappingsChanged)

		FORGE_BUS.addListener(EventPriority.NORMAL, MCommands::register)

		FORGE_BUS.addListener(EventPriority.NORMAL, RedstoneInteractorItem::onUse)

		FORGE_BUS.addListener(EventPriority.NORMAL, NotNormalFood::onInteract)

		FORGE_BUS.addListener(EventPriority.NORMAL, MStructureTags::registerVillagerTrades)

		if (isCuriosLoaded) {
			FORGE_BUS.addListener(EventPriority.NORMAL, ::onCuriosSlotModifiersUpdated)
		}
	}

	private fun setupClient(event: FMLClientSetupEvent) {
		FORGE_BUS.addListener(EventPriority.NORMAL, MatterManager::tooltipEvent)
		FORGE_BUS.addListener(EventPriority.NORMAL, FlywheelMaterials::tooltipEvent)

		FORGE_BUS.addListener(EventPriority.NORMAL, MatteryGUI::onScreenRender)
		FORGE_BUS.addListener(EventPriority.LOWEST, MatteryGUI::onOpenGUIEvent)
		FORGE_BUS.addListener(EventPriority.HIGH, MatteryGUI::onLayerRenderEvent)

		FORGE_BUS.addListener(EventPriority.NORMAL, ShockwaveRenderer::onRender)

		FORGE_BUS.addListener(EventPriority.NORMAL, ::onMovementInputUpdate)
		FORGE_BUS.addListener(EventPriority.NORMAL, ::onScreenOpen)
		FORGE_BUS.addListener(EventPriority.NORMAL, ::onPostScreenInit)
		FORGE_BUS.addListener(EventPriority.NORMAL, ::onMouseDragged)
		FORGE_BUS.addListener(EventPriority.NORMAL, ::onMouseScrolled)
		FORGE_BUS.addListener(EventPriority.LOWEST, ::onClientTickPre)
		FORGE_BUS.addListener(EventPriority.LOWEST, ::onClientTickPost)
		FORGE_BUS.addListener(EventPriority.HIGHEST, ::onClientConnected)
		FORGE_BUS.addListener(EventPriority.HIGHEST, ::onClientDisconnected)
		FORGE_BUS.addListener(EventPriority.NORMAL, ::onClientPostRender)
		FORGE_BUS.addListener(EventPriority.NORMAL, ::tooltipEvent)

		FORGE_BUS.addListener(EventPriority.NORMAL, MatteryTooltipComponents::gatherComponents)

		FORGE_BUS.addListener(EventPriority.NORMAL, QuantumBatteryItem.Companion::clientDisconnect)

		FORGE_BUS.addListener(EventPriority.NORMAL, AndroidMenuKeyMapping::onRenderGuiEvent)
		FORGE_BUS.addListener(EventPriority.NORMAL, AndroidMenuKeyMapping::onMouseClick)

		FORGE_BUS.addListener(EventPriority.NORMAL, AndroidAbilityKeyMapping::onRenderGuiEvent)
		FORGE_BUS.addListener(EventPriority.NORMAL, AndroidAbilityKeyMapping::onRenderLevel)

		FORGE_BUS.addListener(EventPriority.NORMAL, ExosuitModel::onPlayerRendered)

		event.enqueueWork(::recordClientThread)
		event.enqueueWork(::createCursors)
	}
}
