package ru.dbotthepony.kstarbound.network.packets

import com.google.gson.JsonElement
import ru.dbotthepony.kommons.io.readUUID
import ru.dbotthepony.kommons.io.writeBinaryString
import ru.dbotthepony.kommons.io.writeUUID
import ru.dbotthepony.kommons.util.Either
import ru.dbotthepony.kstarbound.client.ClientConnection
import ru.dbotthepony.kstarbound.io.readEither
import ru.dbotthepony.kstarbound.io.readInternedString
import ru.dbotthepony.kstarbound.io.writeEither
import ru.dbotthepony.kstarbound.json.readJsonElement
import ru.dbotthepony.kstarbound.json.writeJsonElement
import ru.dbotthepony.kstarbound.network.IClientPacket
import ru.dbotthepony.kstarbound.network.IServerPacket
import ru.dbotthepony.kstarbound.server.ServerConnection
import ru.dbotthepony.kstarbound.world.World
import ru.dbotthepony.kstarbound.world.entities.AbstractEntity
import java.io.DataInputStream
import java.io.DataOutputStream
import java.util.UUID

class EntityMessageResponsePacket(val response: Either<String, JsonElement>, val id: UUID) : IServerPacket, IClientPacket {
	constructor(stream: DataInputStream, isLegacy: Boolean) : this(
		stream.readEither(isLegacy, { readInternedString() }, { readJsonElement() }),
		stream.readUUID())

	override fun write(stream: DataOutputStream, isLegacy: Boolean) {
		// ah yes, Variant<> in EntityMessagePacket, but Either<> in EntityMessageResponsePacket
		stream.writeEither(response, isLegacy, { writeBinaryString(it) }, { writeJsonElement(it) })
		stream.writeUUID(id)
	}

	override fun play(connection: ServerConnection) {
		connection.enqueue {
			val message = pendingEntityMessages.asMap().remove(id)

			if (message != null) {
				if (response.isLeft) {
					message.completeExceptionally(World.MessageCallException(response.left()))
				} else {
					message.complete(response.right())
				}
			}
		}
	}

	override fun play(connection: ClientConnection) {
		connection.enqueue {
			val message = world?.pendingEntityMessages?.asMap()?.remove(this@EntityMessageResponsePacket.id)

			if (message != null) {
				if (response.isLeft) {
					message.completeExceptionally(World.MessageCallException(response.left()))
				} else {
					message.complete(response.right())
				}
			}
		}
	}
}
