package ru.dbotthepony.mc.otm.storage

import net.minecraft.network.chat.Component
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.core.getValue
import ru.dbotthepony.mc.otm.core.lazy2
import ru.dbotthepony.mc.otm.core.math.toIntSafe
import java.math.BigInteger

class ItemStorageStack private constructor(private val stack: ItemStack, count: BigInteger, mark: Nothing?) : StorageStack<ItemStorageStack>(count) {
	constructor(stack: ItemStack) : this(stack.copy(), BigInteger.valueOf(stack.count.toLong()), null)
	constructor(stack: ItemStack, count: Int) : this(stack.copy(), BigInteger.valueOf(count.toLong()), null)
	constructor(stack: ItemStack, count: Long) : this(stack.copy(), BigInteger.valueOf(count), null)
	constructor(stack: ItemStack, count: BigInteger) : this(stack.copy(), count, null)

	override val type: Type<ItemStorageStack>
		get() = ITEMS

	override fun copy(newCount: BigInteger): ItemStorageStack {
		if (isEmpty)
			return ITEMS.empty

		if (newCount == count)
			return this

		return ItemStorageStack(stack, newCount, null)
	}

	override fun equals(other: Any?): Boolean {
		return other is ItemStorageStack && other.count == count && ItemStack.isSameItemSameTags(stack, other.stack)
	}

	override fun hashCode(): Int {
		return Integer.rotateLeft(count.hashCode(), 12) xor (stack.item.hashCode() * 31 + stack.tag.hashCode())
	}

	override fun equalsWithoutCount(other: StorageStack<*>): Boolean {
		return other is ItemStorageStack && ItemStack.isSameItemSameTags(stack, other.stack)
	}

	override fun hashCodeWithoutCount(): Int {
		return stack.item.hashCode() * 31 + stack.tag.hashCode()
	}

	override val isEmpty: Boolean = stack.isEmpty || super.isEmpty
	override val maxStackSize: BigInteger = BigInteger.valueOf(stack.maxStackSize.toLong())

	val hoverName: Component by lazy2({ toItemStack().hoverName }, { copy() })

	fun toItemStack(count: Int = this.count.toIntSafe()): ItemStack {
		return stack.copyWithCount(count)
	}

	val item: Item get() = stack.item

	companion object {
		val EMPTY get() = ITEMS.empty

		fun unsafe(stack: ItemStack) = ItemStorageStack(stack, BigInteger.valueOf(stack.count.toLong()), null)
		fun unsafe(stack: ItemStack, count: Int) = ItemStorageStack(stack, BigInteger.valueOf(count.toLong()), null)
		fun unsafe(stack: ItemStack, count: Long) = ItemStorageStack(stack, BigInteger.valueOf(count), null)
		fun unsafe(stack: ItemStack, count: BigInteger) = ItemStorageStack(stack, count, null)
	}
}
