package ru.dbotthepony.mc.otm.matter

import net.minecraftforge.eventbus.api.IEventBus
import net.minecraftforge.registries.DeferredRegister
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.core.getValue
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.registry.RegistryDelegate

interface IMatterFunction {
	fun updateValue(self: Int, other: Int): Int
	fun updateValue(self: Decimal, other: Decimal): Decimal
	fun updateValue(self: Double, other: Double): Double

	companion object : IMatterFunction {
		private val registryDelegate = RegistryDelegate<IMatterFunction>("matter_function") { disableSync(); disableSaving() }

		val registryKey get() = registryDelegate.key
		val registry by registryDelegate

		private val registrar = DeferredRegister.create(registryKey, OverdriveThatMatters.MOD_ID)

		init {
			registrar.register("noop") { this }
		}

		val NOOP = this
		val PLUS: IMatterFunction by registrar.register("plus") { SimpleMatterFunction(Int::plus, Double::plus, Decimal::plus) }
		val MINUS: IMatterFunction by registrar.register("minus") { SimpleMatterFunction(Int::minus, Double::minus, Decimal::minus) }
		val DIV: IMatterFunction by registrar.register("div") { SimpleMatterFunction(Int::div, Double::div, Decimal::div) }
		val MUL: IMatterFunction by registrar.register("mul") { SimpleMatterFunction(Int::times, Double::times, Decimal::times) }
		val MOD: IMatterFunction by registrar.register("mod") { SimpleMatterFunction(Int::mod, Double::mod) }
		val AT_LEAST: IMatterFunction by registrar.register("at_least") { SimpleMatterFunction(Int::coerceAtLeast, Double::coerceAtLeast, Decimal::coerceAtLeast) }
		val AT_MOST: IMatterFunction by registrar.register("at_most") { SimpleMatterFunction(Int::coerceAtMost, Double::coerceAtMost, Decimal::coerceAtMost) }
		val REPLACE: IMatterFunction by registrar.register("replace") { SimpleMatterFunction({ _, value -> value }, { _, value -> value }, { _, value -> value }) }

		internal fun register(bus: IEventBus) {
			registrar.register(bus)
			bus.addListener(registryDelegate::build)
		}

		override fun updateValue(self: Int, other: Int): Int {
			return self
		}

		override fun updateValue(self: Decimal, other: Decimal): Decimal {
			return self
		}

		override fun updateValue(self: Double, other: Double): Double {
			return self
		}
	}
}

data class SimpleMatterFunction(
	val int: IntFunction = IntFunction { _, _ -> throw UnsupportedOperationException("Can't do this with Int") },
	val double: DoubleFunction = DoubleFunction { _, _ -> throw UnsupportedOperationException("Can't do this with Double") },
	val decimal: DecimalFunction = DecimalFunction { _, _ -> throw UnsupportedOperationException("Can't do this with Decimal") }
) : IMatterFunction {
	fun interface IntFunction {
		fun update(self: Int, value: Int): Int
	}

	fun interface DoubleFunction {
		fun update(self: Double, value: Double): Double
	}

	fun interface DecimalFunction {
		fun update(self: Decimal, value: Decimal): Decimal
	}

	override fun updateValue(self: Int, other: Int): Int {
		return int.update(self, other)
	}

	override fun updateValue(self: Decimal, other: Decimal): Decimal {
		return decimal.update(self, other)
	}

	override fun updateValue(self: Double, other: Double): Double {
		return double.update(self, other)
	}
}
