package ru.dbotthepony.mc.otm.core

import it.unimi.dsi.fastutil.objects.ObjectIterators
import net.minecraft.ChatFormatting
import net.minecraft.network.chat.Component
import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.client.isShiftDown
import ru.dbotthepony.mc.otm.client.minecraft
import java.util.stream.Stream

interface ITooltippable {
	fun addDescriptionLinesInternal(lines: Stream<out Component>) {
		addDescriptionFunctionsInternal(lines.map { c -> { ObjectIterators.singleton(c.copy()) } })
	}

	fun addDescriptionLinesInternal(vararg lines: Component) {
		lines.forEach { c ->
			addDescriptionFunctionsInternal({ ObjectIterators.singleton(c.copy()) })
		}
	}

	fun addDescriptionLinesInternal(lines: Collection<Component>) {
		lines.forEach { c ->
			addDescriptionFunctionsInternal({ ObjectIterators.singleton(c.copy()) })
		}
	}

	fun addDescriptionFunctionsInternal(lines: Stream<out (ItemStack) -> Iterator<Component>>)
	fun addDescriptionFunctionsInternal(vararg lines: (ItemStack) -> Iterator<Component>)
	fun addDescriptionFunctionsInternal(lines: Collection<(ItemStack) -> Iterator<Component>>)

	fun assembleDescription(itemStack: ItemStack, into: MutableCollection<Component>)

	class Impl : ITooltippable {
		private val descriptionLines = ArrayList<(ItemStack) -> Iterator<Component>>()

		override fun addDescriptionFunctionsInternal(lines: Stream<out (ItemStack) -> Iterator<Component>>) {
			lines.forEach { descriptionLines.add(it) }
		}

		override fun addDescriptionFunctionsInternal(vararg lines: (ItemStack) -> Iterator<Component>) {
			lines.forEach { descriptionLines.add(it) }
		}

		override fun addDescriptionFunctionsInternal(lines: Collection<(ItemStack) -> Iterator<Component>>) {
			lines.forEach { descriptionLines.add(it) }
		}

		override fun assembleDescription(itemStack: ItemStack, into: MutableCollection<Component>) {
			if (descriptionLines.isNotEmpty()) {
				if (!minecraft.window.isShiftDown) {
					into.add(TranslatableComponent("otm.gui.shift_for_more_info").withStyle(ChatFormatting.GRAY).withStyle(ChatFormatting.ITALIC))
				} else {
					for (lines in descriptionLines) {
						into.addAll(lines.invoke(itemStack))
					}
				}
			}
		}
	}
}

fun <T : ITooltippable> T.addDescriptionLines(lines: Stream<out Component>): T {
	addDescriptionLinesInternal(lines)
	return this
}

fun <T : ITooltippable> T.addDescriptionLines(vararg lines: Component): T {
	addDescriptionLinesInternal(lines.stream())
	return this
}

fun <T : ITooltippable> T.addDescriptionLines(lines: Collection<Component>): T {
	addDescriptionLinesInternal(lines)
	return this
}

fun <T : ITooltippable> T.addDescriptionFunctions(lines: Stream<out (ItemStack) -> Iterator<Component>>): T {
	addDescriptionFunctionsInternal(lines)
	return this
}

fun <T : ITooltippable> T.addDescriptionFunctions(vararg lines: (ItemStack) -> Iterator<Component>): T {
	addDescriptionFunctionsInternal(lines.stream())
	return this
}

fun <T : ITooltippable> T.addDescriptionFunctions(line: (ItemStack) -> Iterator<Component>): T {
	addDescriptionFunctionsInternal(line)
	return this
}

fun <T : ITooltippable> T.addDescriptionFunctions(lines: Collection<(ItemStack) -> Iterator<Component>>): T {
	addDescriptionFunctionsInternal(lines)
	return this
}

fun <T : ITooltippable> T.needsNoPowerDescription(formatting: ChatFormatting = ChatFormatting.GRAY): T {
	return addDescriptionLines(TranslatableComponent("otm.needs_no_power").withStyle(formatting))
}
