package ru.dbotthepony.mc.otm.item.matter

import com.google.common.collect.ImmutableList
import net.minecraft.ChatFormatting
import net.minecraft.network.chat.Component
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Rarity
import net.minecraft.world.item.TooltipFlag
import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage
import ru.dbotthepony.mc.otm.capability.matter.PatternInsertFailure
import ru.dbotthepony.mc.otm.capability.matter.PatternInsertInserted
import ru.dbotthepony.mc.otm.capability.matter.PatternInsertStatus
import ru.dbotthepony.mc.otm.capability.matter.PatternInsertUpdated
import ru.dbotthepony.mc.otm.capability.matter.PatternState
import ru.dbotthepony.mc.otm.capability.matter.gatherTooltip
import ru.dbotthepony.mc.otm.capability.matter.getBarColor
import ru.dbotthepony.mc.otm.capability.matter.getBarWidth
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.item.MatteryItem
import ru.dbotthepony.mc.otm.registry.CapabilitiesRegisterListener
import ru.dbotthepony.mc.otm.registry.game.MDataComponentTypes
import java.util.stream.Stream

class PatternStorageItem : MatteryItem, CapabilitiesRegisterListener {
	private val _capacity: () -> Int
	val capacity get() = _capacity.invoke()
	var isCreative: Boolean

	constructor(capacity: () -> Int) : super(Properties().stacksTo(1)) {
		_capacity = capacity
		isCreative = false
	}

	constructor() : super(Properties().rarity(Rarity.EPIC).stacksTo(1)) {
		isCreative = true
		_capacity = { Int.MAX_VALUE }
	}

	override fun registerCapabilities(event: RegisterCapabilitiesEvent) {
		event.registerItem(MatteryCapability.PATTERN_ITEM, { o, _ -> ItemPatternStorageCapability(o) }, this)
	}

	override fun appendHoverText(
		itemStack: ItemStack,
		context: TooltipContext,
		components: MutableList<Component>,
		tooltipType: TooltipFlag
	) {
		itemStack.getCapability(MatteryCapability.PATTERN_ITEM)?.let {
			if (isCreative)
				components.add(TranslatableComponent("otm.item.pattern.infinite.stored", it.storedPatterns).withStyle(ChatFormatting.GRAY))
			else
				components.add(TranslatableComponent("otm.item.pattern.stored", it.storedPatterns, it.patternCapacity).withStyle(ChatFormatting.GRAY))

			it.gatherTooltip(context, components, tooltipType)
		}

		super.appendHoverText(itemStack, context, components, tooltipType)
	}

	override fun isBarVisible(p_150899_: ItemStack): Boolean {
		if (isCreative)
			return false

		return p_150899_.getCapability(MatteryCapability.PATTERN_ITEM) != null
	}

	override fun getBarWidth(p_150900_: ItemStack): Int {
		if (isCreative)
			return 13

		return p_150900_.getCapability(MatteryCapability.PATTERN_ITEM)?.getBarWidth() ?: super.getBarWidth(p_150900_)
	}

	override fun getBarColor(p_150901_: ItemStack): Int {
		if (isCreative)
			return 0

		return p_150901_.getCapability(MatteryCapability.PATTERN_ITEM)?.getBarColor() ?: super.getBarColor(p_150901_)
	}

	inner class ItemPatternStorageCapability(val stack: ItemStack) : IPatternStorage {
		override val patternCapacity: Int get() {
			return this@PatternStorageItem.capacity
		}

		override val storedPatterns: Int get() {
			return stack[MDataComponentTypes.PATTERNS]?.size ?: 0
		}

		override val patterns: Stream<PatternState> get() {
			return stack[MDataComponentTypes.PATTERNS]?.stream() ?: Stream.empty()
		}

		override fun insertPattern(
			pattern: PatternState,
			onlyUpdate: Boolean,
			simulate: Boolean
		): PatternInsertStatus {
			val patterns = ArrayList(stack[MDataComponentTypes.PATTERNS] ?: listOf())

			for ((i, ePattern) in patterns.withIndex()) {
				if (ePattern.id == pattern.id) {
					if (simulate) {
						return PatternInsertUpdated(pattern, ePattern)
					}

					patterns[i] = pattern
					stack[MDataComponentTypes.PATTERNS] = ImmutableList.copyOf(patterns)
					return PatternInsertUpdated(pattern, ePattern)
				}
			}

			if (onlyUpdate || patternCapacity <= patterns.size)
				return PatternInsertFailure

			if (!simulate) {
				patterns.add(pattern)
				stack[MDataComponentTypes.PATTERNS] = ImmutableList.copyOf(patterns)
			}

			return PatternInsertInserted(pattern)
		}
	}
}
