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

import com.mojang.blaze3d.platform.InputConstants
import com.mojang.datafixers.util.Either
import it.unimi.dsi.fastutil.floats.FloatConsumer
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.screens.Screen
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.client.playGuiClickSound
import ru.dbotthepony.mc.otm.client.render.MatterySprite
import ru.dbotthepony.mc.otm.client.render.RenderGravity
import ru.dbotthepony.mc.otm.client.render.UVWindingOrder
import ru.dbotthepony.mc.otm.client.render.WidgetLocation
import ru.dbotthepony.mc.otm.client.render.renderRect
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
import ru.dbotthepony.mc.otm.client.screen.panels.button.AbstractButtonPanel
import ru.dbotthepony.mc.otm.client.screen.panels.input.TextInputPanel
import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.math.HSVColor
import ru.dbotthepony.mc.otm.core.math.RGBAColor
import java.util.function.Consumer
import kotlin.math.roundToInt

open class ColorBoxPanel<out S : Screen>(
	screen: S,
	parent: EditablePanel<*>?,
	x: Float,
	y: Float,
	width: Float = 64f,
	height: Float = 64f,
	protected val callback: Consumer<HSVColor>? = null,
) : EditablePanel<S>(screen, parent, x, y, width, height) {
	var backgroundColor = RGBAColor.RED
		private set
	var markerPos = backgroundColor.toHSV()
		protected set

	fun setColor(color: Either<RGBAColor, HSVColor>) {
		color.map(
			{ markerPos = it.toHSV(); if (it.canRepresentHue()) backgroundColor = HSVColor(it.toHSV().hue, 1f, 1f).toRGBA() },
			{ markerPos = it; backgroundColor = HSVColor(it.hue, 1f, 1f).toRGBA() })
	}

	var isPressed = false
		private set

	override fun shouldRenderTooltips(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float): Boolean {
		return super.shouldRenderTooltips(graphics, mouseX, mouseY, partialTick) || isPressed
	}

	protected open fun onPickedColor(color: HSVColor) {
		callback?.accept(color)
	}

	protected fun pickColor(mouseX: Double, mouseY: Double) {
		val (x, y) = screenToLocal(mouseX, mouseY)

		val saturation = 1f - x.coerceIn(0f, width) / width
		val value = 1f - y.coerceIn(0f, height) / height

		markerPos = HSVColor(backgroundColor.toHSV().hue, saturation, value)
		onPickedColor(markerPos)
	}

	override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
		if (button == InputConstants.MOUSE_BUTTON_LEFT) {
			if (!isPressed) {
				isPressed = true
				grabMouseInput = true

				pickColor(x, y)
				playGuiClickSound()
			}

			return true
		}

		return super.mouseClickedInner(x, y, button)
	}

	override fun mouseDraggedInner(x: Double, y: Double, button: Int, xDelta: Double, yDelta: Double): Boolean {
		if (isPressed && button == InputConstants.MOUSE_BUTTON_LEFT) {
			pickColor(x, y)
			return true
		}

		return super.mouseDraggedInner(x, y, button, xDelta, yDelta)
	}

	override fun mouseReleasedInner(x: Double, y: Double, button: Int): Boolean {
		if (button == InputConstants.MOUSE_BUTTON_LEFT) {
			if (isPressed) {
				isPressed = false
				grabMouseInput = false
			}

			return true
		}

		return super.mouseReleasedInner(x, y, button)
	}

	override fun innerRender(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
		graphics.renderRect(0f, 0f, width, height, color = RGBAColor.WHITE)
		GRADIENT_LEFT.render(graphics, 0f, 0f, width, height, color = backgroundColor)
		GRADIENT_DOWN.render(graphics, 0f, 0f, width, height, color = RGBAColor.BLACK)

		val x = (1f - markerPos.saturation) * width
		val y = (1f - markerPos.value) * height

		LINE_VERTICAL.render(graphics, x = x - 1f, height = height)
		LINE_HORIZONTAL.render(graphics, y = y - 1f, width = width)
		LINE_CROSS.render(graphics, x = x - 1f, y = y - 1f)
	}

	companion object {
		 val GRADIENT_UP = MatterySprite(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/gradient_v.png"), 0f, 0f, 32f, 256f, 32f, 256f)
		 val GRADIENT_DOWN = GRADIENT_UP.copy(winding = UVWindingOrder.FLIP)
		 val GRADIENT_RIGHT = MatterySprite(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/gradient_h.png"), 0f, 0f, 256f, 32f, 256f, 32f)
		 val GRADIENT_LEFT = GRADIENT_RIGHT.copy(winding = UVWindingOrder.FLOP)

		val LINE_VERTICAL = WidgetLocation.MISC.sprite(36f, 0f, 3f, 3f)
		val LINE_HORIZONTAL = WidgetLocation.MISC.sprite(36f, 3f, 3f, 3f)
		val LINE_CROSS = WidgetLocation.MISC.sprite(36f, 6f, 3f, 3f)
	 }
}

abstract class AbstractColorWangPanel<out S : Screen>(
	screen: S,
	parent: EditablePanel<*>?,
	x: Float = 0f,
	y: Float = 0f,
	width: Float = 40f,
	height: Float = 10f,
	protected val callback: Consumer<RGBAColor>? = null,
) : EditablePanel<S>(screen, parent, x, y, width, height) {
	abstract val leftColor: RGBAColor
	abstract val rightColor: RGBAColor
	abstract val wangPosition: Float
	abstract fun setColor(color: Either<RGBAColor, HSVColor>)
	protected abstract fun onWangInput(newPosition: Float)

	init {
		scissor = true
	}

	var isPressed = false
		private set

	protected fun updateColor(mouseX: Double) {
		onWangInput((screenToLocal(mouseX, 0.0).x / width).coerceIn(0f, 1f))
	}

	override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
		if (button == InputConstants.MOUSE_BUTTON_LEFT) {
			if (!isPressed) {
				isPressed = true
				grabMouseInput = true

				updateColor(x)
				playGuiClickSound()
			}

			return true
		}

		return super.mouseClickedInner(x, y, button)
	}

	override fun mouseDraggedInner(x: Double, y: Double, button: Int, xDelta: Double, yDelta: Double): Boolean {
		if (isPressed && button == InputConstants.MOUSE_BUTTON_LEFT) {
			updateColor(x)
			return true
		}

		return super.mouseDraggedInner(x, y, button, xDelta, yDelta)
	}

	override fun mouseReleasedInner(x: Double, y: Double, button: Int): Boolean {
		if (button == InputConstants.MOUSE_BUTTON_LEFT) {
			if (isPressed) {
				isPressed = false
				grabMouseInput = false
			}

			return true
		}

		return super.mouseReleasedInner(x, y, button)
	}

	protected fun renderGradients(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
		ColorBoxPanel.GRADIENT_RIGHT.render(graphics, 0f, 0f, width, height, color = rightColor)
		ColorBoxPanel.GRADIENT_LEFT.render(graphics, 0f, 0f, width, height, color = leftColor)
	}

	protected fun renderWang(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
		if (wangPosition in 0f .. 1f) {
			ColorBoxPanel.LINE_VERTICAL.render(graphics, x = wangPosition * width - 1f, height = height)
		}
	}

	override fun innerRender(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
		renderGradients(graphics, mouseX, mouseY, partialTick)
		renderWang(graphics, mouseX, mouseY, partialTick)
	}
}

open class RedColorWangPanel<out S : Screen>(
	screen: S,
	parent: EditablePanel<*>?,
	x: Float = 0f,
	y: Float = 0f,
	width: Float = 40f,
	height: Float = 10f,
	callback: Consumer<RGBAColor>? = null,
) : AbstractColorWangPanel<S>(screen, parent, x, y, width, height, callback) {
	override var leftColor: RGBAColor = RGBAColor.BLACK
		protected set
	override var rightColor: RGBAColor = RGBAColor.RED
		protected set
	override var wangPosition: Float = 0f
		protected set

	override fun onWangInput(newPosition: Float) {
		val color = leftColor.copy(red = newPosition)
		wangPosition = newPosition
		callback?.accept(color)
	}

	override fun setColor(color: Either<RGBAColor, HSVColor>) {
		@Suppress("name_shadowing")
		val color = color.map({ it }, { it.toRGBA() })
		leftColor = color.copy(red = 0f, alpha = 1f)
		rightColor = color.copy(red = 1f, alpha = 1f)
		wangPosition = color.red
	}
}

open class GreenColorWangPanel<out S : Screen>(
	screen: S,
	parent: EditablePanel<*>?,
	x: Float = 0f,
	y: Float = 0f,
	width: Float = 40f,
	height: Float = 10f,
	callback: Consumer<RGBAColor>? = null,
) : AbstractColorWangPanel<S>(screen, parent, x, y, width, height, callback) {
	override var leftColor: RGBAColor = RGBAColor.BLACK
		protected set
	override var rightColor: RGBAColor = RGBAColor.GREEN
		protected set
	override var wangPosition: Float = 0f
		protected set

	override fun onWangInput(newPosition: Float) {
		val color = leftColor.copy(green = newPosition)
		wangPosition = newPosition
		callback?.accept(color)
	}

	override fun setColor(color: Either<RGBAColor, HSVColor>) {
		@Suppress("name_shadowing")
		val color = color.map({ it }, { it.toRGBA() })
		leftColor = color.copy(green = 0f, alpha = 1f)
		rightColor = color.copy(green = 1f, alpha = 1f)
		wangPosition = color.green
	}
}

open class BlueColorWangPanel<out S : Screen>(
	screen: S,
	parent: EditablePanel<*>?,
	x: Float = 0f,
	y: Float = 0f,
	width: Float = 40f,
	height: Float = 10f,
	callback: Consumer<RGBAColor>? = null,
) : AbstractColorWangPanel<S>(screen, parent, x, y, width, height, callback) {
	override var leftColor: RGBAColor = RGBAColor.BLACK
		protected set
	override var rightColor: RGBAColor = RGBAColor.BLUE
		protected set
	override var wangPosition: Float = 0f
		protected set

	override fun onWangInput(newPosition: Float) {
		val color = leftColor.copy(blue = newPosition)
		wangPosition = newPosition
		callback?.accept(color)
	}

	override fun setColor(color: Either<RGBAColor, HSVColor>) {
		@Suppress("name_shadowing")
		val color = color.map({ it }, { it.toRGBA() })
		leftColor = color.copy(blue = 0f, alpha = 1f)
		rightColor = color.copy(blue = 1f, alpha = 1f)
		wangPosition = color.blue
	}
}

open class HueWangPanel<out S : Screen>(
	screen: S,
	parent: EditablePanel<*>?,
	x: Float = 0f,
	y: Float = 0f,
	width: Float = 40f,
	height: Float = 10f,
	protected val hueCallback: FloatConsumer? = null,
) : AbstractColorWangPanel<S>(screen, parent, x, y, width, height) {
	override val leftColor: RGBAColor get() = RGBAColor.WHITE
	override val rightColor: RGBAColor get() = RGBAColor.WHITE
	override var wangPosition: Float = 1f
		protected set

	override fun setColor(color: Either<RGBAColor, HSVColor>) {
		color.map(
			{
				if (it.canRepresentHue()) {
					wangPosition = it.toHSV().hue / 360f
				}
			},
			{
				wangPosition = it.hue / 360f
			}
		)
	}

	override fun onWangInput(newPosition: Float) {
		wangPosition = newPosition
		hueCallback?.accept(newPosition * 360f)
	}

	override fun innerRender(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
		HSV_BAR.render(graphics, 0f, 0f, width, height)
		renderWang(graphics, mouseX, mouseY, partialTick)
	}

	companion object {
		val HSV_BAR = MatterySprite(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/hsv.png"), 0f, 0f, 256f, 16f, 256f, 16f)
	}
}

open class SaturationWangPanel<out S : Screen>(
	screen: S,
	parent: EditablePanel<*>?,
	x: Float = 0f,
	y: Float = 0f,
	width: Float = 40f,
	height: Float = 10f,
	protected val saturationCallback: FloatConsumer? = null,
) : AbstractColorWangPanel<S>(screen, parent, x, y, width, height) {
	override var leftColor: RGBAColor = RGBAColor.WHITE
		protected set
	override var rightColor: RGBAColor = RGBAColor.WHITE
		protected set
	override var wangPosition: Float = 1f
		protected set

	override fun onWangInput(newPosition: Float) {
		wangPosition = newPosition
		saturationCallback?.accept(newPosition)
	}

	override fun setColor(color: Either<RGBAColor, HSVColor>) {
		color.map(
			{
				val hsv = it.toHSV()

				if (it.canRepresentHue()) {
					leftColor = hsv.copy(saturation = 0f).toRGBA()
					rightColor = hsv.copy(saturation = 1f).toRGBA()
				} else {
					leftColor = hsv.copy(hue = leftColor.toHSV().hue, saturation = 0f).toRGBA()
					rightColor = hsv.copy(hue = rightColor.toHSV().hue, saturation = 1f).toRGBA()
				}

				wangPosition = hsv.saturation
			},
			{ hsv ->
				leftColor = hsv.copy(saturation = 0f).toRGBA()
				rightColor = hsv.copy(saturation = 1f).toRGBA()
				wangPosition = hsv.saturation
			}
		)
	}
}

open class ValueWangPanel<out S : Screen>(
	screen: S,
	parent: EditablePanel<*>?,
	x: Float = 0f,
	y: Float = 0f,
	width: Float = 40f,
	height: Float = 10f,
	protected val valueCallback: FloatConsumer? = null,
) : AbstractColorWangPanel<S>(screen, parent, x, y, width, height) {
	override var leftColor: RGBAColor = RGBAColor.BLACK
		protected set
	override var rightColor: RGBAColor = RGBAColor.WHITE
		protected set
	override var wangPosition: Float = 1f
		protected set

	override fun onWangInput(newPosition: Float) {
		wangPosition = newPosition
		valueCallback?.accept(newPosition)
	}

	override fun setColor(color: Either<RGBAColor, HSVColor>) {
		color.map(
			{
				val hsv = it.toHSV()

				if (it.canRepresentHue()) {
					leftColor = hsv.copy(value = 0f).toRGBA()
					rightColor = hsv.copy(value = 1f).toRGBA()
				} else {
					leftColor = hsv.copy(hue = leftColor.toHSV().hue, value = 0f).toRGBA()
					rightColor = hsv.copy(hue = rightColor.toHSV().hue, value = 1f).toRGBA()
				}

				wangPosition = hsv.value
			},
			{ hsv ->
				leftColor = hsv.copy(value = 0f).toRGBA()
				rightColor = hsv.copy(value = 1f).toRGBA()
				wangPosition = hsv.value
			}
		)
	}
}

open class ColorPalettePanel<out S : Screen>(
	screen: S,
	parent: EditablePanel<*>?,
	x: Float = 0f,
	y: Float = 0f,
	width: Float = 64f,
	height: Float = 64f,
	protected val callback: Consumer<RGBAColor>? = null
) : EditablePanel<S>(screen, parent, x, y, width, height) {
	open fun onColorChoose(color: RGBAColor) {
		callback?.accept(color)
	}

	inner class Button(val color: RGBAColor) : AbstractButtonPanel<S>(screen, this@ColorPalettePanel, 0f, 0f, 8f, 8f) {
		init {
			tooltips.add(TextComponent("${color.redInt}, ${color.greenInt}, ${color.blueInt}"))
			tooltips.add(TextComponent(color.toHexStringRGB()))
		}

		override fun onClick(mouseButton: Int) {
			onColorChoose(color)
		}

		override fun innerRender(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
			graphics.renderRect(0f, 0f, width, height, color = RGBAColor.BLACK)
			graphics.renderRect(1f, 1f, width - 2f, height - 2f, color = color)
		}

		override fun compareTo(other: EditablePanel<*>): Int {
			return super.compareTo(other).let {
				if (it != 0 || other !is Button)
					it
				else
					color.compareTo(other.color)
			}
		}
	}

	override fun performLayout() {
		super.performLayout()

		var x = 0f
		var y = 0f

		for (children in visibleChildren) {
			if (children is Button) {
				if (x != 0f && x + children.width > width) {
					y += 9f
					x = 0f
				}

				children.x = x
				children.y = y
				x += 9f
			}
		}
	}
}

open class ColorPickerPanel<out S : Screen>(
	screen: S,
	parent: EditablePanel<*>?,
	x: Float = 0f,
	y: Float = 0f,
	width: Float = 164f,
	height: Float = 118f,
	var callback: Consumer<RGBAColor>? = null
) : EditablePanel<S>(screen, parent, x, y, width, height) {
	open fun onColorChanged(color: RGBAColor) {
		callback?.accept(color)
	}

	var currentColor: Either<RGBAColor, HSVColor> = Either.left(RGBAColor.WHITE)
		protected set

	fun setColor(color: Either<RGBAColor, HSVColor>) {
		currentColor = color
		hexInput.text = color.map({ it }, { it.toRGBA() }).toHexStringRGB()
		updateWangs(color)
	}

	protected fun updateWangs(color: Either<RGBAColor, HSVColor>) {
		box.setColor(color)

		for (wang in wangs)
			wang.update(color)
	}

	protected open fun onPaletteChoose(color: RGBAColor) {
		setColor(Either.left(color))
		onColorChanged(color)
	}

	protected open fun onColorBoxChoose(color: HSVColor) {
		setColor(Either.right(color))
		onColorChanged(color.toRGBA())
	}

	protected open fun onWangChoose(color: RGBAColor) {
		setColor(Either.left(color))
		onColorChanged(color)
	}

	protected open fun onHueChoose(hue: Float) {
		val current = currentColor.map({ it.toHSV() }, { it })
		val new = current.copy(hue = hue)
		setColor(Either.right(new))
		onColorChanged(new.toRGBA())
	}

	protected open fun onSaturationChoose(saturation: Float) {
		val current = currentColor.map({ it.toHSV() }, { it })
		val new = current.copy(saturation = saturation)
		setColor(Either.right(new))
		onColorChanged(new.toRGBA())
	}

	protected open fun onValueChoose(value: Float) {
		val current = currentColor.map({ it.toHSV() }, { it })
		val new = current.copy(value = value)
		setColor(Either.right(new))
		onColorChanged(new.toRGBA())
	}

	val topStrip = EditablePanel(screen, this, 0f, 0f, width = width, height = 70f)
	val middleStrip = EditablePanel(screen, this)
	val palette = ColorPalettePanel(screen, this, callback = { onPaletteChoose(it) })

	val hexInput = object : TextInputPanel<S>(screen, middleStrip, width = 50f) {
		init {
			dock = Dock.RIGHT
		}

		override fun onFocusChanged() {
			if (!isFocusedThis) {
				val newColor = RGBAColor.fromHexStringRGB(text)

				if (newColor == null) {
					text = currentColor.map({ it }, { it.toRGBA() }).toHexStringRGB()
				} else {
					setColor(Either.left(newColor))
					onColorChanged(newColor)
				}
			}
		}

		override fun acceptsCharacter(codepoint: Char, mods: Int): Boolean {
			return RGBAColor.isHexCharacter(codepoint)
		}
	}

	init {
		topStrip.dock = Dock.TOP
		middleStrip.dock = Dock.TOP
		palette.dock = Dock.FILL
		palette.dockTop = 2f
		middleStrip.dockTop = 2f

		for (color in paletteColors) {
			palette.Button(color)
		}
	}

	val box = ColorBoxPanel(screen, topStrip, 0f, 0f, width = 70f, height = 70f, callback = { onColorBoxChoose(it) })
	val wangCanvas = EditablePanel(screen, topStrip, width = 80f)

	inner class WangLine(label: String, val wang: AbstractColorWangPanel<S>, val text: (color: Either<RGBAColor, HSVColor>) -> Component?) {
		val canvas = EditablePanel(screen, wangCanvas, height = 10f)
		val label = Label(screen, canvas, width = 10f, text = TranslatableComponent("otm.gui.color.short.$label"))
		val textLabel = Label(screen, canvas, width = 25f)

		init {
			this.wang.parent = canvas
			this.wang.width = 45f

			this.label.childrenOrder = 0
			this.wang.childrenOrder = 1
			this.textLabel.childrenOrder = 2

			this.canvas.dock = Dock.TOP
			this.canvas.dockTop = 2f

			this.label.dock = Dock.LEFT
			this.label.dockRight = 2f

			this.wang.dock = Dock.LEFT
			this.wang.dockRight = 2f

			this.textLabel.dock = Dock.LEFT
			this.textLabel.align = RenderGravity.CENTER_LEFT

			this.label.tooltips.add(TranslatableComponent("otm.gui.color.full.$label"))
			this.label.align = RenderGravity.CENTER_RIGHT
		}

		fun update(color: Either<RGBAColor, HSVColor>) {
			wang.setColor(color)

			text.invoke(color)?.let {
				textLabel.text = it
			}
		}
	}

	val red = WangLine("red", RedColorWangPanel(screen, wangCanvas, callback = { onWangChoose(it) })) { TextComponent((it.map({ it }, { it.toRGBA() }).red * 255f).roundToInt().toString()) }
	val green = WangLine("green", GreenColorWangPanel(screen, wangCanvas, callback = { onWangChoose(it) })) { TextComponent((it.map({ it }, { it.toRGBA() }).green * 255f).roundToInt().toString()) }
	val blue = WangLine("blue", BlueColorWangPanel(screen, wangCanvas, callback = { onWangChoose(it) })) { TextComponent((it.map({ it }, { it.toRGBA() }).blue * 255f).roundToInt().toString()) }

	val hue = WangLine("hue", HueWangPanel(screen, wangCanvas, hueCallback = { onHueChoose(it) })) { it.map({ if (it.canRepresentHue()) it.toHSV() else null }, { it })?.let { TextComponent(it.hue.roundToInt().toString()) } }
	val saturation = WangLine("saturation", SaturationWangPanel(screen, wangCanvas, saturationCallback = { onSaturationChoose(it) })) { it.map({ if (it.canRepresentHue()) it.toHSV() else null }, { it })?.let { TextComponent((it.saturation * 100f).roundToInt().toString() + "%") } }
	val value = WangLine("value", ValueWangPanel(screen, wangCanvas, valueCallback = { onValueChoose(it) })) { it.map({ if (it.canRepresentHue()) it.toHSV() else null }, { it })?.let { TextComponent((it.value * 100f).roundToInt().toString() + "%") } }

	val wangs = listOf(red, green, blue, hue, saturation, value)

	init {
		box.dock = Dock.LEFT
		wangCanvas.dock = Dock.RIGHT
		red.canvas.dockTop = 0f

		setColor(Either.right(HSVColor.WHITE))
	}

	companion object {
		val paletteColors = listOf(
			RGBAColor.rgb(0x9b59b6L), // Amethyst
			RGBAColor.rgb(0x010101L), // Black
			RGBAColor.rgb(0x0000ffL), // Blue
			RGBAColor.rgb(0x8B4513L), // Brown
			RGBAColor.rgb(0xe67e22L), // Carrot
			RGBAColor.rgb(0xD2691EL), // Chocolate
			RGBAColor.rgb(0xecf0f1L), // Clouds
			RGBAColor.rgb(0xFF7F50L), // Coral
			RGBAColor.rgb(0xDC143CL), // Crimson
			RGBAColor.rgb(0x00FFFFL), // Cyan
			RGBAColor.rgb(0x008B8BL), // DarkCyan
			RGBAColor.rgb(0xBDB76BL), // DarkGold
			RGBAColor.rgb(0xB8860BL), // DarkGoldenRod
			RGBAColor.rgb(0x006400L), // DarkGreen
			RGBAColor.rgb(0x16a085L), // DarkGreen
			RGBAColor.rgb(0x8B008BL), // DarkMagenta
			RGBAColor.rgb(0x556B2FL), // DarkOlive
			RGBAColor.rgb(0xFF8C00L), // DarkOrange
			RGBAColor.rgb(0x8B0000L), // DarkRed
			RGBAColor.rgb(0xE9967AL), // DarkSalmon
			RGBAColor.rgb(0x9400D3L), // DarkViolet
			RGBAColor.rgb(0xFF1493L), // DeepPink
			RGBAColor.rgb(0x00BFFFL), // DeepSkyBlue
			RGBAColor.rgb(0x2ecc71L), // Emerald
			RGBAColor.rgb(0xB22222L), // FireBrick
			RGBAColor.rgb(0x228B22L), // ForestGreen
			RGBAColor.rgb(0xFF00FFL), // Fuchsia
			RGBAColor.rgb(0xDCDCDCL), // Gainsboro
			RGBAColor.rgb(0xFFD700L), // Gold
			RGBAColor.rgb(0xDAA520L), // GoldenRod
			RGBAColor.rgb(0x00B000L), // Green
			RGBAColor.rgb(0x808080L), // Grey
			RGBAColor.rgb(0xFF69B4L), // HotPink
			RGBAColor.rgb(0x4B0082L), // Indigo
			RGBAColor.rgb(0xF0E68CL), // Khaki
			RGBAColor.rgb(0xE6E6FAL), // Lavender
			RGBAColor.rgb(0xFF9FF7L), // LavenderRose
			RGBAColor.rgb(0xD3D3D3L), // LightGrey
			RGBAColor.rgb(0x87CEFAL), // LightSkyBlue
			RGBAColor.rgb(0xFFFFE0L), // LightYellow
			RGBAColor.rgb(0x00ff00L), // Lime
			RGBAColor.rgb(0x32CD32L), // LimeGreen
			RGBAColor.rgb(0xBA55D3L), // MediumOrchid
			RGBAColor.rgb(0x9370DBL), // MediumPurple
			RGBAColor.rgb(0x7B68EEL), // MediumSlateBlue
			RGBAColor.rgb(0x808000L), // Olive
			RGBAColor.rgb(0x6B8E23L), // OliveGreen
			RGBAColor.rgb(0xFFA500L), // Orange
			RGBAColor.rgb(0xDA70D6L), // Orchid
			RGBAColor.rgb(0xDB7093L), // PaleVioletRed
			RGBAColor.rgb(0xCD853FL), // Peru
			RGBAColor.rgb(0xFFC0CBL), // Pink
			RGBAColor.rgb(0xB0E0E6L), // PowderBlue
			RGBAColor.rgb(0xd35400L), // Pumpkin
			RGBAColor.rgb(0x800080L), // Purple
			RGBAColor.rgb(0xff0000L), // Red
			RGBAColor.rgb(0x4169E1L), // RoyalBlue
			RGBAColor.rgb(0xFA8072L), // Salmon
			RGBAColor.rgb(0xF4A460L), // SandyBrown
			RGBAColor.rgb(0x2E8B57L), // SeaGreen
			RGBAColor.rgb(0xA0522DL), // Sienna
			RGBAColor.rgb(0xbdc3c7L), // Silver
			RGBAColor.rgb(0x87CEEBL), // SkyBlue
			RGBAColor.rgb(0x708090L), // SlateGrey
			RGBAColor.rgb(0x4682B4L), // SteelBlue
			RGBAColor.rgb(0xf1c40fL), // SunFlower
			RGBAColor.rgb(0x008080L), // Teal
			RGBAColor.rgb(0xD8BFD8L), // Thistle
			RGBAColor.rgb(0xEE82EEL), // Violet
		)

		fun <S : MatteryScreen<*>> frame(screen: S, callback: Consumer<RGBAColor>, color: RGBAColor = RGBAColor.RED, title: Component? = TranslatableComponent("otm.gui.color_picker")): FramePanel<S> {
			return FramePanel.padded(screen, 164f, 118f, title).also {
				ColorPickerPanel(screen, it, 0f, 0f, callback = callback).also {
					it.dock = Dock.FILL
					it.setColor(Either.left(color))
				}

				screen.addPanel(it)
				it.toScreenCenter()
				it.behaveAsWindow()
				it.popup()
			}
		}
	}
}
