package ru.dbotthepony.kstarbound.test

import it.unimi.dsi.fastutil.io.FastByteArrayInputStream
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import ru.dbotthepony.kommons.io.Vector2fCodec
import ru.dbotthepony.kommons.vector.Vector2f
import ru.dbotthepony.kstarbound.network.syncher.BasicNetworkedElement
import ru.dbotthepony.kstarbound.network.syncher.EventCounterElement
import ru.dbotthepony.kstarbound.network.syncher.NetworkedGroup
import ru.dbotthepony.kstarbound.network.syncher.MasterElement
import ru.dbotthepony.kstarbound.network.syncher.networkedBoolean
import ru.dbotthepony.kstarbound.network.syncher.networkedDouble
import ru.dbotthepony.kstarbound.network.syncher.networkedEnum
import ru.dbotthepony.kstarbound.network.syncher.networkedFixedPoint
import ru.dbotthepony.kstarbound.network.syncher.networkedFloat
import ru.dbotthepony.kstarbound.network.syncher.networkedPointer
import ru.dbotthepony.kstarbound.network.syncher.networkedSignedInt
import ru.dbotthepony.kstarbound.network.syncher.networkedUnsignedInt

// reflects tests defined in original sources
// because they are quite comprehensive
object NetworkedElementTests {
	enum class TestEnum {
		VALUE1,
		VALUE2,
		VALUE3;
	}

	@Test
	@DisplayName("NetworkedElement")
	fun testAllTypes() {
		val masterField1 = networkedSignedInt()
		val masterField2 = networkedUnsignedInt()
		val masterField3 = networkedPointer()
		val masterField4 = networkedFloat()
		val masterField5 = networkedDouble()
		val masterField6 = networkedFixedPoint(0.01)
		val masterField7 = networkedFixedPoint(0.01) // no difference
		val masterField8 = networkedBoolean()
		val masterField9 = networkedEnum(TestEnum.VALUE1)
		val masterField10 = EventCounterElement()
		val masterField11 = BasicNetworkedElement(Vector2f.ZERO, Vector2fCodec)

		val master = MasterElement(NetworkedGroup())
		master.upstream.add(masterField1)
		master.upstream.add(masterField2)
		master.upstream.add(masterField3)
		master.upstream.add(masterField4)
		master.upstream.add(masterField5)
		master.upstream.add(masterField6)
		master.upstream.add(masterField7)
		master.upstream.add(masterField8)
		master.upstream.add(masterField9)
		master.upstream.add(masterField10)
		master.upstream.add(masterField11)

		masterField1.accept(567)
		masterField2.accept(17000)
		masterField3.accept(22222)
		masterField4.accept(1.55)
		masterField5.accept(1.12345678910111213)
		masterField6.accept(2000.62)
		masterField7.accept(2000.62)
		masterField8.accept(true)
		masterField9.accept(TestEnum.VALUE2)
		masterField10.trigger()
		masterField11.accept(Vector2f(2.0f, 2.0f))

		assertEquals(567, masterField1.get())
		assertEquals(17000, masterField2.get())
		assertEquals(22222, masterField3.get())
		assertEquals(1.55, masterField4.get())
		assertEquals(1.12345678910111213, masterField5.get())
		assertEquals(2000.62, masterField6.get())
		assertEquals(2000.62, masterField7.get())
		assertEquals(true, masterField8.get())
		assertEquals(TestEnum.VALUE2, masterField9.get())
		assertTrue(masterField10.pullOccurred())
		assertEquals(Vector2f(2.0f, 2.0f), masterField11.get())

		val slaveField1 = networkedSignedInt()
		val slaveField2 = networkedUnsignedInt()
		val slaveField3 = networkedPointer()
		val slaveField4 = networkedFloat()
		val slaveField5 = networkedDouble()
		val slaveField6 = networkedFixedPoint(0.01)
		val slaveField7 = networkedFixedPoint(0.01) // no difference
		val slaveField8 = networkedBoolean()
		val slaveField9 = networkedEnum(TestEnum.VALUE1)
		val slaveField10 = EventCounterElement()
		val slaveField11 = BasicNetworkedElement(Vector2f.ZERO, Vector2fCodec)

		val slave = MasterElement(NetworkedGroup())
		slave.upstream.add(slaveField1)
		slave.upstream.add(slaveField2)
		slave.upstream.add(slaveField3)
		slave.upstream.add(slaveField4)
		slave.upstream.add(slaveField5)
		slave.upstream.add(slaveField6)
		slave.upstream.add(slaveField7)
		slave.upstream.add(slaveField8)
		slave.upstream.add(slaveField9)
		slave.upstream.add(slaveField10)
		slave.upstream.add(slaveField11)

		val result = master.write().first

		slave.read(result)

		assertEquals(567, slaveField1.get())
		assertEquals(17000, slaveField2.get())
		assertEquals(22222, slaveField3.get())
		assertEquals(1.55f, slaveField4.getAsFloat())
		assertEquals(1.12345678910111213, slaveField5.get())
		assertEquals(2000.62f, slaveField6.getAsFloat())
		assertEquals(2000.62f, slaveField7.getAsFloat()) // due to precision fuckery, 2000.62 turns into 2000.620000001
		assertEquals(true, slaveField8.get())
		assertEquals(TestEnum.VALUE2, slaveField9.get())
		assertTrue(slaveField10.pullOccurred())
		assertEquals(Vector2f(2.0f, 2.0f), slaveField11.get())
	}
}
