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

import net.minecraft.client.gui.screens.Screen
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
import ru.dbotthepony.mc.otm.client.screen.panels.util.AnalogScrollBarPanel
import ru.dbotthepony.mc.otm.client.screen.panels.util.BackgroundPanel
import ru.dbotthepony.mc.otm.client.screen.panels.util.ScrollBarConstants

open class ScrollbarBackgroundPanel<out S : Screen>(
	screen: S,
	parent: EditablePanel<*>?,
	x: Float = 0f,
	y: Float = 0f,
	width: Float = 30f,
	height: Float = 30f,
	alwaysShowScrollbar: Boolean = false,
	autoResizeForScrollbar: Boolean = true,
	autoMoveForScrollbar: Boolean = true,
	scrollStep: Float = AbstractSlotPanel.SIZE,
) : BackgroundPanel<S>(screen, parent, x, y, width, height) {
	/**
	 * Whenever is to hide scrollbar when there is nothing to scroll
	 */
	var alwaysShowScrollbar = alwaysShowScrollbar
		set(value) {
			if (field != value) {
				field = value
				determineScrollbarVisible()
			}
		}

	private var lastResizedForScrollbar: Boolean = false
	private var lastMovedForScrollbar: Boolean = false

	/**
	 * Whenever is to auto resize width when scrollbar has to be shown
	 *
	 * Has no effect if [alwaysShowScrollbar] is true
	 */
	var autoResizeForScrollbar = autoResizeForScrollbar
		set(value) {
			if (field != value) {
				field = value
				determineScrollbarVisible()
			}
		}

	/**
	 * Whenever is to auto move panel along X axis when scrollbar has to be shown (given no [dock] is [Dock.NONE])
	 *
	 * Has no effect if [alwaysShowScrollbar] is true
	 */
	var autoMoveForScrollbar = autoMoveForScrollbar
		set(value) {
			if (field != value) {
				field = value
				determineScrollbarVisible()
			}
		}

	private fun getMaxScroll(it: AnalogScrollBarPanel<*>): Float {
		return (canvas.childrenRectHeight - canvas.height).coerceAtLeast(0f)
	}

	private fun onScrollUpdate(it: AnalogScrollBarPanel<*>, old: Float, new: Float) {
		this.canvas.yOffset = -new
	}

	val scrollbar = AnalogScrollBarPanel(screen, this, this::getMaxScroll, smoothScrollCallback = this::onScrollUpdate, isSlim = true, scrollStep = scrollStep)

	fun determineScrollbarVisible() {
		if (alwaysShowScrollbar) {
			scrollbar.visible = true

			if (lastResizedForScrollbar) {
				width -= scrollbar.width
				lastResizedForScrollbar = false
			}

			if (lastMovedForScrollbar) {
				x += scrollbar.width
				lastMovedForScrollbar = false
			}
		} else {
			if (canvas.childrenRectHeight > (height - dockPadding.top - dockPadding.bottom)) {
				if (!scrollbar.visible) {
					scrollbar.visible = true

					if (autoResizeForScrollbar) {
						width += scrollbar.width
						lastResizedForScrollbar = true
					}

					if (autoMoveForScrollbar && dock == Dock.NONE) {
						x -= scrollbar.width
						lastMovedForScrollbar = true
					}
				}
			} else {
				if (scrollbar.visible) {
					scrollbar.visible = false

					if (lastResizedForScrollbar) {
						width -= scrollbar.width
						lastResizedForScrollbar = false
					}

					if (lastMovedForScrollbar) {
						x += scrollbar.width
						lastMovedForScrollbar = false
					}
				}
			}
		}
	}

	val canvas = object : EditablePanel<S>(screen, this@ScrollbarBackgroundPanel) {
		init {
			scissor = true
		}

		override fun performLayout() {
			super.performLayout()
			determineScrollbarVisible()
		}

		override fun mouseScrolledInner(x: Double, y: Double, scroll: Double): Boolean {
			scrollbar.mouseScrolledInner(x, y, scroll)
			return true
		}
	}

	fun addPanel(panel: EditablePanel<*>) {
		panel.parent = canvas
	}

	init {
		scrollbar.dock = Dock.RIGHT
		canvas.dock = Dock.FILL
		scrollbar.visible = alwaysShowScrollbar
	}

	companion object {
		fun <S : Screen> padded(
			screen: S,
			parent: EditablePanel<*>?,
			x: Float = 0f,
			y: Float = 0f,
			width: Float = 30f,
			height: Float = 30f,
			alwaysShowScrollbar: Boolean = false,
			autoResizeForScrollbar: Boolean = true,
			autoMoveForScrollbar: Boolean = true,
			scrollStep: Float = AbstractSlotPanel.SIZE,
		) = ScrollbarBackgroundPanel(screen, parent, x, y, width + 6f + (if (alwaysShowScrollbar) ScrollBarConstants.SLIM_WIDTH else 0f), height + 6f, alwaysShowScrollbar, autoResizeForScrollbar, autoMoveForScrollbar, scrollStep)

		fun <S : Screen> paddedCenter(
			screen: S,
			parent: EditablePanel<*>?,
			x: Float = 0f,
			y: Float = 0f,
			width: Float = 30f,
			height: Float = 30f,
			alwaysShowScrollbar: Boolean = false,
			autoResizeForScrollbar: Boolean = true,
			autoMoveForScrollbar: Boolean = true,
			scrollStep: Float = AbstractSlotPanel.SIZE,
		) = ScrollbarBackgroundPanel(screen, parent, x - 3f, y - 3f - (if (alwaysShowScrollbar) ScrollBarConstants.SLIM_WIDTH / 2f else 0f), width + 6f + (if (alwaysShowScrollbar) ScrollBarConstants.SLIM_WIDTH else 0f), height + 6f, alwaysShowScrollbar, autoResizeForScrollbar, autoMoveForScrollbar, scrollStep)
	}
}
