package ru.dbotthepony.mc.otm.network.synchronizer

import ru.dbotthepony.mc.otm.core.FloatSupplier
import java.io.DataInputStream
import java.io.DataOutputStream
import java.util.function.BooleanSupplier
import java.util.function.DoubleSupplier
import java.util.function.IntSupplier
import java.util.function.LongSupplier
import java.util.function.Supplier
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty

sealed interface IField<V> : ReadOnlyProperty<Any?, V>, Supplier<V>, () -> V {
	fun observe(): Boolean
	fun markDirty()
	fun markDirty(endpoint: FieldSynchronizer.Endpoint)
	val value: V
	val isRemoved: Boolean

	fun remove()

	fun write(stream: DataOutputStream, endpoint: FieldSynchronizer.Endpoint)
	fun read(stream: DataInputStream)

	override fun getValue(thisRef: Any?, property: KProperty<*>): V {
		return this.value
	}

	override fun get(): V {
		return value
	}

	override fun invoke(): V {
		return value
	}
}

interface IFloatProperty {
	operator fun getValue(thisRef: Any?, property: KProperty<*>): Float
}

sealed interface IFloatField : IField<Float>, FloatSupplier {
	val float: Float
	val property: IFloatProperty

	override val value: Float
		get() = float

	@Deprecated("Use type specific Supplier interface")
	override fun get(): Float {
		return float
	}

	override fun getAsFloat(): Float {
		return float
	}

	@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
	override fun getValue(thisRef: Any?, property: KProperty<*>): Float {
		return float
	}
}

interface IDoubleProperty {
	operator fun getValue(thisRef: Any?, property: KProperty<*>): Double
}

sealed interface IDoubleField : IField<Double>, DoubleSupplier {
	val double: Double
	val property: IDoubleProperty

	@Deprecated("Use type specific Supplier interface")
	override fun get(): Double {
		return double
	}

	override val value: Double
		get() = double

	override fun getAsDouble(): Double {
		return double
	}

	@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
	override fun getValue(thisRef: Any?, property: KProperty<*>): Double {
		return double
	}
}

interface IIntProperty {
	operator fun getValue(thisRef: Any?, property: KProperty<*>): Int
}

sealed interface IIntField : IField<Int>, IntSupplier {
	val int: Int
	val property: IIntProperty

	@Deprecated("Use type specific Supplier interface")
	override fun get(): Int {
		return int
	}

	override val value: Int
		get() = int

	override fun getAsInt(): Int {
		return int
	}

	@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
	override fun getValue(thisRef: Any?, property: KProperty<*>): Int {
		return int
	}
}

interface ILongProperty {
	operator fun getValue(thisRef: Any?, property: KProperty<*>): Long
}

sealed interface ILongField : IField<Long>, LongSupplier {
	val long: Long
	val property: ILongProperty

	@Deprecated("Use type specific Supplier interface")
	override fun get(): Long {
		return long
	}

	override val value: Long
		get() = long

	override fun getAsLong(): Long {
		return long
	}

	@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
	override fun getValue(thisRef: Any?, property: KProperty<*>): Long {
		return long
	}
}

interface IBooleanProperty {
	operator fun getValue(thisRef: Any?, property: KProperty<*>): Boolean
}

sealed interface IBooleanField : IField<Boolean>, BooleanSupplier {
	val boolean: Boolean
	val property: IBooleanProperty

	@Deprecated("Use type specific Supplier interface")
	override fun get(): Boolean {
		return boolean
	}

	override val value: Boolean
		get() = boolean

	override fun getAsBoolean(): Boolean {
		return boolean
	}

	@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
	override fun getValue(thisRef: Any?, property: KProperty<*>): Boolean {
		return boolean
	}
}
