package ru.dbotthepony.kstarbound.defs

import com.google.gson.JsonElement
import com.google.gson.JsonObject
import ru.dbotthepony.kstarbound.Registries
import ru.dbotthepony.kstarbound.io.readInternedString
import ru.dbotthepony.kstarbound.json.builder.IStringSerializable
import ru.dbotthepony.kstarbound.json.readJsonElement
import ru.dbotthepony.kstarbound.world.entities.AbstractEntity
import ru.dbotthepony.kstarbound.world.entities.ItemDropEntity
import ru.dbotthepony.kstarbound.world.entities.player.PlayerEntity
import ru.dbotthepony.kstarbound.world.entities.tile.PlantEntity
import ru.dbotthepony.kstarbound.world.entities.tile.PlantPieceEntity
import ru.dbotthepony.kstarbound.world.entities.tile.WorldObject
import java.io.DataInputStream

enum class EntityType(override val jsonName: String, val storeName: String, val canBeCreatedByClient: Boolean, val canBeSpawnedByClient: Boolean) : IStringSerializable {
	PLANT("plant", "PlantEntity", false, false) {
		override fun fromNetwork(stream: DataInputStream, isLegacy: Boolean): AbstractEntity {
			return PlantEntity(stream, isLegacy)
		}

		override fun fromStorage(data: JsonObject): AbstractEntity {
			return PlantEntity(data)
		}
	},

	OBJECT("object", "ObjectEntity", false, true) {
		override fun fromNetwork(stream: DataInputStream, isLegacy: Boolean): AbstractEntity {
			val name = stream.readInternedString()
			val parameters = stream.readJsonElement()
			val config = Registries.worldObjects.getOrThrow(name)
			return WorldObject.create(config, parameters = parameters as? JsonObject ?: JsonObject())!!
		}

		override fun fromStorage(data: JsonObject): AbstractEntity {
			return WorldObject.fromJson(data)
		}
	},

	VEHICLE("vehicle", "VehicleEntity", false, true) {
		override fun fromNetwork(stream: DataInputStream, isLegacy: Boolean): AbstractEntity {
			TODO("VEHICLE")
		}

		override fun fromStorage(data: JsonObject): AbstractEntity {
			TODO("VEHICLE")
		}
	},

	ITEM_DROP("itemDrop", "ItemDropEntity", false, true) {
		override fun fromNetwork(stream: DataInputStream, isLegacy: Boolean): AbstractEntity {
			return ItemDropEntity(stream, isLegacy)
		}

		override fun fromStorage(data: JsonObject): AbstractEntity {
			return ItemDropEntity(data)
		}
	},

	PLANT_DROP("plantDrop", "PlantDropEntity", false, false) {
		override fun fromNetwork(stream: DataInputStream, isLegacy: Boolean): AbstractEntity {
			return PlantPieceEntity(stream, isLegacy)
		}

		override fun fromStorage(data: JsonObject): AbstractEntity {
			return PlantPieceEntity(data)
		}
	},

	PROJECTILE("projectile", "ProjectileEntity", true, true) {
		override fun fromNetwork(stream: DataInputStream, isLegacy: Boolean): AbstractEntity {
			TODO("PROJECTILE")
		}

		override fun fromStorage(data: JsonObject): AbstractEntity {
			TODO("PROJECTILE")
		}
	},

	STAGEHAND("stagehand", "StagehandEntity", false, false) {
		override fun fromNetwork(stream: DataInputStream, isLegacy: Boolean): AbstractEntity {
			TODO("STAGEHAND")
		}

		override fun fromStorage(data: JsonObject): AbstractEntity {
			TODO("STAGEHAND")
		}
	},

	MONSTER("monster", "MonsterEntity", false, false) {
		override fun fromNetwork(stream: DataInputStream, isLegacy: Boolean): AbstractEntity {
			TODO("MONSTER")
		}

		override fun fromStorage(data: JsonObject): AbstractEntity {
			TODO("MONSTER")
		}
	},

	NPC("npc", "NpcEntity", false, false) {
		override fun fromNetwork(stream: DataInputStream, isLegacy: Boolean): AbstractEntity {
			TODO("NPC")
		}

		override fun fromStorage(data: JsonObject): AbstractEntity {
			TODO("NPC")
		}
	},

	PLAYER("player", "PlayerEntity", true, false) {
		override fun fromNetwork(stream: DataInputStream, isLegacy: Boolean): AbstractEntity {
			return PlayerEntity(stream, isLegacy)
		}

		override fun fromStorage(data: JsonObject): AbstractEntity {
			return PlayerEntity(data)
		}
	};

	abstract fun fromNetwork(stream: DataInputStream, isLegacy: Boolean): AbstractEntity
	abstract fun fromStorage(data: JsonObject): AbstractEntity
}
