package ru.dbotthepony.kstarbound.defs.animation

import com.google.common.collect.ImmutableMap
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import it.unimi.dsi.fastutil.objects.Object2ObjectAVLTreeMap
import ru.dbotthepony.kstarbound.json.builder.IStringSerializable
import ru.dbotthepony.kstarbound.json.builder.JsonFactory
import kotlin.properties.Delegates

@JsonFactory
data class AnimatedPartsDefinition(
	val stateTypes: ImmutableMap<String, StateType> = ImmutableMap.of(),
	val parts: ImmutableMap<String, Part> = ImmutableMap.of(),
) {
	enum class AnimationMode(override val jsonName: String) : IStringSerializable {
		END("end"),
		TRANSITION("transition"),
		LOOP("loop");
	}

	@JsonFactory
	data class StateType(
		val default: String = "",
		val priority: Double = 0.0,
		val enabled: Boolean = true,
		val states: ImmutableMap<String, State> = ImmutableMap.of(),
		val properties: JsonObject = JsonObject(),
	) {
		val sortedStates: ImmutableMap<String, State> = states.entries.stream()
			.sorted { o1, o2 -> o1.key.compareTo(o2.key) }
			.collect(ImmutableMap.toImmutableMap({ it.key }, { it.value }))

		@JsonFactory
		data class State(
			val frames: Int = 1,
			val cycle: Double = 1.0,
			val mode: AnimationMode = AnimationMode.END,
			val transition: String = "",
			val properties: JsonObject = JsonObject(),
			val frameProperties: ImmutableMap<String, JsonArray> = ImmutableMap.of(),
		) {
			var name by Delegates.notNull<String>()
			var index = 0
		}

		init {
			var index = 0

			for ((k, v) in sortedStates) {
				v.name = k
				v.index = index++

				if (v.mode == AnimationMode.TRANSITION && v.transition !in states) {
					throw IllegalArgumentException("State '$k' has specified TRANSITION as mode, however, it points to non-existing state '${v.transition}'!")
				}
			}
		}
	}

	@JsonFactory
	data class Part(
		val properties: JsonObject = JsonObject(),
		val partStates: ImmutableMap<String, ImmutableMap<String, State>> = ImmutableMap.of(),
	) {
		@JsonFactory
		data class State(
			val properties: JsonObject = JsonObject(),
			val frameProperties: ImmutableMap<String, JsonArray> = ImmutableMap.of(),
		)
	}
}