package ru.dbotthepony.kstarbound.defs.animation

import com.google.common.collect.ImmutableList
import com.google.common.collect.ImmutableMap
import ru.dbotthepony.kommons.math.RGBAColor
import ru.dbotthepony.kommons.util.AABB
import ru.dbotthepony.kommons.util.Either
import ru.dbotthepony.kommons.util.KOptional
import ru.dbotthepony.kommons.vector.Vector2d
import ru.dbotthepony.kstarbound.Registry
import ru.dbotthepony.kstarbound.defs.AssetPath
import ru.dbotthepony.kstarbound.defs.image.SpriteReference
import ru.dbotthepony.kstarbound.json.builder.JsonFactory

@JsonFactory
data class AnimationDefinition(
	val frames: SpriteReference? = null,
	val variants: Int? = null,
	val frameNumber: Int? = null,
	val animationCycle: Double? = null,
	val offset: Vector2d? = null,

	val animatedParts: AnimatedPartsDefinition? = null,

	val sounds: ImmutableMap<String, Either<ImmutableList<String>, CustomSound>> = ImmutableMap.of(),
	val transformationGroups: ImmutableMap<String, Transform> = ImmutableMap.of(),
	val rotationGroups: ImmutableMap<String, Rotation> = ImmutableMap.of(),
	val particleEmitters: ImmutableMap<String, AnimationParticles> = ImmutableMap.of(),
	val lights: ImmutableMap<String, Light> = ImmutableMap.of(),
	val effects: ImmutableMap<String, Effect> = ImmutableMap.of(),

	val globalTagDefaults: ImmutableMap<String, String> = ImmutableMap.of(),
	val partTagDefaults: ImmutableMap<String, ImmutableMap<String, String>> = ImmutableMap.of(),
) {
	@JsonFactory
	data class Effect(
		val type: String,
		val time: Double = 0.0,
		val directives: String,
	)

	@JsonFactory
	data class AnimationParticles(
		val emissionRate: Double = 1.0,
		val emissionRateVariance: Double = 0.0,
		val offsetRegion: AABB? = null,
		val anchorPart: String? = null,
		val rotationGroup: String? = null,
		val rotationCenter: Vector2d? = null,
		val transformationGroups: ImmutableList<String> = ImmutableList.of(),
		val particles: ImmutableList<AnimationParticle>,
		val burstCount: Int = 1,
		val randomSelectCount: Int = particles.size,
		val active: Boolean = false,
	) {
		init {
			require(burstCount >= 0) { "Negative burstCount: $burstCount" }
			require(randomSelectCount >= 0) { "Negative randomSelectCount: $randomSelectCount" }
		}
	}

	@JsonFactory
	data class AnimationParticle(
		val particle: Either<Registry.Ref<ParticleConfig>, ParticleConfig.JsonData>,
		val count: Int = 1,
		val offset: Vector2d = Vector2d.ZERO,
		val flip: Boolean = false,
	) {
		init {
			require(count >= 0) { "Negative count: $count" }
		}
	}

	@JsonFactory
	data class Light(
		val active: Boolean = true,
		val position: Vector2d = Vector2d.ZERO,
		val color: RGBAColor = RGBAColor.WHITE,
		val anchorPart: String? = null,
		val transformationGroups: ImmutableList<String> = ImmutableList.of(),
		val rotationGroup: String? = null,
		val rotationCenter: Vector2d? = null,
		val pointLight: Boolean = false,
		val pointBeam: Float = 0f,
		val beamAmbience: Float = 0f,
		val pointAngle: Double = 0.0,

		// sigh
		val flickerPeriod: Double? = null,
		val flickerMinIntensity: Double = 0.0,
		val flickerMaxIntensity: Double = 0.0,
		val flickerPeriodVariance: Double = 0.0,
		val flickerIntensityVariance: Double = 0.0,
	)

	@JsonFactory
	data class CustomSound(
		val pool: ImmutableList<AssetPath> = ImmutableList.of(),
		val position: Vector2d = Vector2d.ZERO,
		val volume: Double = 1.0,
		val volumeRampTime: Double = 0.0,
		val pitchMultiplier: Double = 1.0,
		val pitchMultiplierRampTime: Double = 0.0,
		val rangeMultiplier: Double = 1.0,
	)

	@JsonFactory
	data class Rotation(
		val angularVelocity: Double = 0.0,
		val rotationCenter: Vector2d = Vector2d.ZERO,
	)

	@JsonFactory
	data class Transform(
		val interpolated: Boolean = false
	)
}
