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

import it.unimi.dsi.fastutil.floats.Float2ObjectArrayMap
import net.minecraft.network.chat.Component
import ru.dbotthepony.kommons.math.RGBAColor
import ru.dbotthepony.mc.otm.client.render.ChartLevelLabels
import ru.dbotthepony.mc.otm.client.render.ChartMouseLabels
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
import ru.dbotthepony.mc.otm.client.render.renderChart
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
import ru.dbotthepony.mc.otm.core.RandomSource2Generator
import ru.dbotthepony.mc.otm.core.chart.DecimalHistoryChart
import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.math.clusterize
import ru.dbotthepony.mc.otm.core.util.formatPower
import ru.dbotthepony.mc.otm.core.util.formatTickDuration
import kotlin.math.absoluteValue

open class DecimalHistoryChartPanel<out S : MatteryScreen<*>>(
	screen: S,
	parent: EditablePanel<*>,
	val chart: DecimalHistoryChart,
	val formatText: (Decimal) -> Component = { TextComponent(it.toString(2)) },
	x: Float = 0f,
	y: Float = 0f,
	width: Float = 10f,
	height: Float = 10f
) : EditablePanel<S>(screen, parent, x, y, width, height) {
	override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
		val maximum = chart.max()
		val normalized: FloatArray
		val levelLabels: ChartLevelLabels

		if (maximum.isZero || maximum.isInfinite) {
			normalized = FloatArray(chart.width) {
				if (chart[it].isInfinite) 1f else 0.0f
			}

			levelLabels = ChartLevelLabels(
				labels = mapOf(
					1f to TextComponent("∞"),
					// 0f to formatText(Decimal.ZERO),
				),
				font = font
			)
		} else {
			normalized = FloatArray(chart.width) { (chart[it] / maximum).toFloat() }

			val map = Float2ObjectArrayMap<Component>()

			map[1f] = formatText(maximum)

			for (cluster in chart.asIterable().clusterize(randomGenerator)) {
				val perc = (cluster.center / maximum).toFloat()

				if (map.keys.none { (it - perc).absoluteValue < 0.08f }) {
					map[perc] = cluster.center.formatPower()
				}
			}

			/*
			if (map.keys.none { (it - 0.75f).absoluteValue < 0.1f })
				map[0.75f] = formatText(maximum * 0.75)

			if (map.keys.none { (it - 0.5f).absoluteValue < 0.1f })
				map[0.5f] = formatText(maximum * 0.5)

			if (map.keys.none { (it - 0.25f).absoluteValue < 0.1f })
				map[0.25f] = formatText(maximum * 0.25)
			 */

			levelLabels = ChartLevelLabels(
				labels = map,
				font = font
			)
		}

		graphics.renderRect(0f, 0f, this.width, this.height, color = RGBAColor.BLACK)

		renderChart(
			graphics.pose,
			listOf(normalized to RGBAColor.WHITE),
			width,
			height - font.lineHeight - 4f,
			y = font.lineHeight.toFloat() + 4f,
			labels = ChartMouseLabels(
				mouseX - absoluteX,
				mouseY - absoluteY,
				{
					val result = ArrayList<Component>()
					result.add(formatText(chart[it]))

					if (chart.resolution != 1 && chart[it].isFinite && chart[it].isNotZero) {
						result.add(TranslatableComponent("otm.gui.total_approx", formatText(chart[it] * chart.resolution)))
					}

					result.add(TextComponent(""))

					if (chart.resolution <= 20) {
						result.add(TranslatableComponent("otm.gui.ago", formatTickDuration(it * chart.resolution, false)))
					} else {
						val useLongFormat = chart.resolution * chart.width / 20 > 99 * 60
						result.add(TranslatableComponent("otm.gui.ago", formatTickDuration(it * chart.resolution, useLongFormat) + "-" + formatTickDuration((it + 1) * chart.resolution, useLongFormat)))
						result.add(TextComponent("(${formatTickDuration(chart.resolution, useLongFormat)})"))
					}

					result
				},
				font,
			),
			levelLabels = levelLabels
		)
	}

	companion object {

	}
}
