package ru.dbotthepony.mc.otm

import net.minecraft.util.TimeSource
import ru.dbotthepony.mc.otm.core.util.formatTickDuration
import java.util.function.LongSupplier

/**
 * just to avoid origin in future
 */

val systemTime = SystemTime()

/**
 * nanoseconds elapsed
 */
val nanoTime get() = systemTime.nanos

/**
 * microseconds elapsed
 */
val microTime get() = systemTime.micros

/**
 * milliseconds elapsed
 */
val milliTime get() = systemTime.millis

/**
 * seconds elapsed
 */
val secondTime get() = systemTime.seconds

val microTimeD get() = systemTime.microsD
val milliTimeD get() = systemTime.millisD
val secondTimeD get() = systemTime.secondsD

val microTimeF get() = systemTime.microsF
val milliTimeF get() = systemTime.millisF
val secondTimeF get() = systemTime.secondsF

/**
 * just to avoid origin in future
 *
 * All properties return time since this object creation (they are always positive and zero based)
 *
 * The only issue can arise is JVM running for longer than 292 years (as described in [System.nanoTime])
 */
class SystemTime : LongSupplier, TimeSource.NanoTimeSource {
	private val origin = System.nanoTime()

	val nanos get() = System.nanoTime() - origin
	val micros get() = (System.nanoTime() - origin) / 1_000L
	val millis get() = (System.nanoTime() - origin) / 1_000_000L
	val seconds get() = (System.nanoTime() - origin) / 1_000_000_000L

	val microsD get() = (System.nanoTime() - origin) / 1_000.0
	val millisD get() = (System.nanoTime() - origin) / 1_000_000.0
	val secondsD get() = (System.nanoTime() - origin) / 1_000_000_000.0

	val microsF get() = (System.nanoTime() - origin) / 1_000f
	val millisF get() = (System.nanoTime() - origin) / 1_000_000f
	val secondsF get() = (System.nanoTime() - origin) / 1_000_000_000f

	override fun getAsLong(): Long {
		return nanos
	}

	fun formatted(longFormat: Boolean = true) = formatTickDuration((millis / 50L).toInt(), longFormat)

	override fun equals(other: Any?): Boolean {
		return other === this || other is SystemTime && other.origin == origin
	}

	override fun hashCode(): Int {
		return origin.hashCode()
	}

	override fun toString(): String {
		return "SystemTime[at ${origin}ns, ${secondsD}s elapsed]"
	}
}
