package ru.dbotthepony.mc.otm.client.screen.panels.button

import net.minecraft.ChatFormatting
import net.minecraft.client.gui.screens.Screen
import net.minecraft.network.chat.Component
import ru.dbotthepony.kommons.math.RGBAColor
import ru.dbotthepony.kommons.util.Delegate
import ru.dbotthepony.kommons.util.value
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.client.render.IGUIRenderable
import ru.dbotthepony.mc.otm.client.render.UVWindingOrder
import ru.dbotthepony.mc.otm.client.render.Widgets15
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.menu.input.IPlayerInputWithFeedback

abstract class BooleanButtonPanel<out S : Screen>(
	screen: S,
	parent: EditablePanel<*>?,
	x: Float = 0f,
	y: Float = 0f,
	width: Float,
	height: Float,
	val isChecked: Delegate<Boolean>,
) : ButtonPanel<S>(screen, parent, x, y, width, height) {
	abstract val tooltipActive: Component?
	abstract val tooltipInactive: Component?
	abstract val iconActive: IGUIRenderable?
	abstract val iconInactive: IGUIRenderable?
	open val iconDisabledActive: IGUIRenderable?
		get() = iconActive
	open val iconDisabledInactive: IGUIRenderable?
		get() = iconInactive

	override var isDisabled: Boolean
		get() {
			if (isChecked is IPlayerInputWithFeedback<Boolean>) {
				return !isChecked.test(minecraft.player!!)
			} else {
				return super.isDisabled
			}
		}
		set(value) { super.isDisabled = value }

	override val icon: IGUIRenderable?
		get() = if (isChecked.get()) {
			if (isDisabled) iconDisabledActive else iconActive
		} else {
			if (isDisabled) iconDisabledInactive else iconInactive
		}

	override fun onClick(mouseButton: Int) {
		isChecked.accept(!isChecked.get())
	}

	override fun innerRenderTooltips(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float): Boolean {
		if (isHovered) {
			val tooltipActive = tooltipActive
			val tooltipInactive = tooltipInactive

			if (tooltipActive != null || tooltipInactive != null || tooltips.isNotEmpty()) {
				val tooltips = ArrayList<Component>(2 + this.tooltips.size)

				if (this.tooltips.isNotEmpty()) {
					tooltips.addAll(this.tooltips)

					if (tooltipActive != null || tooltipInactive != null)
						tooltips.add(SPACE)
				}

				if (tooltipActive != null) {
					if (isChecked.get())
						tooltips.add(TranslatableComponent("otm.gui.tooltip.enum.active", tooltipActive.copy().withStyle(ChatFormatting.WHITE)))
					else
						tooltips.add(tooltipActive.copy().withStyle(ChatFormatting.GRAY))
				}

				if (tooltipInactive != null) {
					if (isChecked.get())
						tooltips.add(tooltipInactive.copy().withStyle(ChatFormatting.GRAY))
					else
						tooltips.add(TranslatableComponent("otm.gui.tooltip.enum.active", tooltipInactive.copy().withStyle(ChatFormatting.WHITE)))
				}

				graphics.renderComponentTooltip(font, tooltips, mouseX.toInt(), mouseY.toInt())
			}
		}

		return super.innerRenderTooltips(graphics, mouseX, mouseY, partialTick)
	}

	open class Radio<out S : Screen>(
		screen: S,
		parent: EditablePanel<*>? = null,
		x: Float = 0f,
		y: Float = 0f,
		prop: Delegate<Boolean>,
	) : BooleanButtonPanel<S>(screen, parent, x, y, 15f, 15f, prop) {
		override val disabledSprite: IGUIRenderable
			get() = Widgets15.RADIO_DISABLED
		override val pressedSprite: IGUIRenderable
			get() = Widgets15.RADIO_PRESSED
		override val hoveredSprite: IGUIRenderable
			get() = Widgets15.RADIO_HOVERED
		override val idleSprite: IGUIRenderable
			get() = Widgets15.RADIO_IDLE

		override var tooltipActive: Component? = null
		override var tooltipInactive: Component? = null
		override val iconActive: IGUIRenderable?
			get() = Widgets15.RADIO_ICON
		override val iconInactive: IGUIRenderable?
			get() = null
		override val iconDisabledActive: IGUIRenderable?
			get() = Widgets15.RADIO_ICON_DISABLED
		override val iconSpaceReservation: SpaceReservation
			get() = SpaceReservation.ICON_ONLY
	}

	open class Checkbox<out S : Screen>(
		screen: S,
		parent: EditablePanel<*>? = null,
		x: Float = 0f,
		y: Float = 0f,
		prop: Delegate<Boolean>,
	) : BooleanButtonPanel<S>(screen, parent, x, y, 15f, 15f, prop) {
		constructor(
			screen: S,
			parent: EditablePanel<*>?,
			x: Float = 0f,
			y: Float = 0f,
			prop: Delegate<Boolean>,
			label: Component
		) : this(screen, parent, x, y, prop) {
			width = font.width(label) + 24f
			height = 18f

			this.label = label
		}

		constructor(
			screen: S,
			parent: EditablePanel<*>?,
			prop: Delegate<Boolean>,
			label: Component
		) : this(screen, parent, 0f, 0f, prop, label)

		constructor(
			screen: S,
			parent: EditablePanel<*>?,
			prop: Delegate<Boolean>,
		) : this(screen, parent, 0f, 0f, prop)

		var displayUncheckedIcon = true

		override var label: Component? = null
		override var labelColor: RGBAColor = RGBAColor.WHITE

		override val iconSpaceReservation: SpaceReservation = SpaceReservation.ICON_AND_TEXT

		override var tooltipActive: Component? = null
		override val tooltipInactive: Component? = null
		override val iconActive: IGUIRenderable
			get() = Widgets15.CHECKED
		override val iconInactive: IGUIRenderable?
			get() = if (displayUncheckedIcon) Widgets15.UNCHECKED else null

		override val iconDisabledActive: IGUIRenderable
			get() = Widgets15.CHECKED_DISABLED
		override val iconDisabledInactive: IGUIRenderable?
			get() = if (displayUncheckedIcon) Widgets15.UNCHECKED_DISABLED else null
	}

	open class Simple<out S : Screen>(
		screen: S,
		parent: EditablePanel<*>? = null,
		x: Float = 0f,
		y: Float = 0f,
		width: Float,
		height: Float,
		prop: Delegate<Boolean>,
		override var iconActive: IGUIRenderable? = null,
		override var iconInactive: IGUIRenderable? = null,
		override var tooltipActive: Component? = null,
		override var tooltipInactive: Component? = null,
	) : BooleanButtonPanel<S>(screen, parent, x, y, width, height, prop) {
		override var label: Component? = null
		override var labelColor: RGBAColor = RGBAColor.WHITE

		override var iconWinding: UVWindingOrder = UVWindingOrder.NORMAL
		override var iconOnLeft: Boolean = true
		override val iconSpaceReservation: SpaceReservation = SpaceReservation.DEFAULT
	}

	companion object {
		private val SPACE = TextComponent("")

		fun <S : Screen> square18(
			screen: S,
			parent: EditablePanel<*>?,
			x: Float = 0f,
			y: Float = 0f,
			prop: Delegate<Boolean>,
			iconActive: IGUIRenderable? = null,
			iconInactive: IGUIRenderable? = null,
			tooltipActive: Component? = null,
			tooltipInactive: Component? = null,
		): Simple<S> {
			return Simple(screen, parent, x, y, 18f, 18f, prop, iconActive, iconInactive, tooltipActive, tooltipInactive)
		}

		fun <S : Screen> square15(
			screen: S,
			parent: EditablePanel<*>?,
			x: Float = 0f,
			y: Float = 0f,
			prop: Delegate<Boolean>,
			iconActive: IGUIRenderable? = null,
			iconInactive: IGUIRenderable? = null,
			tooltipActive: Component? = null,
			tooltipInactive: Component? = null,
		): Simple<S> {
			return Simple(screen, parent, x, y, 15f, 15f, prop, iconActive, iconInactive, tooltipActive, tooltipInactive)
		}

		fun <S : Screen> square8(
			screen: S,
			parent: EditablePanel<*>?,
			x: Float = 0f,
			y: Float = 0f,
			prop: Delegate<Boolean>,
			iconActive: IGUIRenderable? = null,
			iconInactive: IGUIRenderable? = null,
			tooltipActive: Component? = null,
			tooltipInactive: Component? = null,
		): Simple<S> {
			return Simple(screen, parent, x, y, 8f, 8f, prop, iconActive, iconInactive, tooltipActive, tooltipInactive)
		}

		fun <S : Screen> square18(
			screen: S,
			parent: EditablePanel<*>?,
			prop: Delegate<Boolean>,
			iconActive: IGUIRenderable? = null,
			iconInactive: IGUIRenderable? = null,
			tooltipActive: Component? = null,
			tooltipInactive: Component? = null,
		): Simple<S> {
			return Simple(screen, parent, 0f, 0f, 18f, 18f, prop, iconActive, iconInactive, tooltipActive, tooltipInactive)
		}

		fun <S : Screen> square15(
			screen: S,
			parent: EditablePanel<*>?,
			prop: Delegate<Boolean>,
			iconActive: IGUIRenderable? = null,
			iconInactive: IGUIRenderable? = null,
			tooltipActive: Component? = null,
			tooltipInactive: Component? = null,
		): Simple<S> {
			return Simple(screen, parent, 0f, 0f, 15f, 15f, prop, iconActive, iconInactive, tooltipActive, tooltipInactive)
		}

		fun <S : Screen> square8(
			screen: S,
			parent: EditablePanel<*>?,
			prop: Delegate<Boolean>,
			iconActive: IGUIRenderable? = null,
			iconInactive: IGUIRenderable? = null,
			tooltipActive: Component? = null,
			tooltipInactive: Component? = null,
		): Simple<S> {
			return Simple(screen, parent, 0f, 0f, 8f, 8f, prop, iconActive, iconInactive, tooltipActive, tooltipInactive)
		}
	}
}
