package ru.dbotthepony.mc.otm.data.codec

import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.advancements.critereon.DamagePredicate
import net.minecraft.advancements.critereon.DamageSourcePredicate
import net.minecraft.advancements.critereon.EntityPredicate
import net.minecraft.advancements.critereon.MinMaxBounds
import kotlin.reflect.KProperty1

private val dealtReceived: Codec<Pair<MinMaxBounds.Doubles, MinMaxBounds.Doubles>> = RecordCodecBuilder.create {
	it.group(
		MinMaxBounds.Doubles.CODEC.fieldOf("dealt").forGetter { it.first },
		MinMaxBounds.Doubles.CODEC.fieldOf("taken").forGetter { it.second },
	).apply(it, ::Pair)
}

val DamagePredicateCodec: Codec<DamagePredicate> = RecordCodecBuilder.create {
	it.group(
		dealtReceived.fieldOf("damage").forGetter { it.dealtDamage to it.takenDamage },
		Codec.BOOL.optionalFieldOf("blocked").forGetter { it.blocked },
		EntityPredicate.CODEC.optionalFieldOf("source_entity").forGetter { it.sourceEntity },
		DamageSourcePredicate.CODEC.optionalFieldOf("type").forGetter { it.type },
	).apply(it) { damage, blocked, source, type -> DamagePredicate(damage.first, damage.second, source, blocked, type) }
}

fun <V, T1> simpleCodec(factory: (T1) -> V, field1: KProperty1<V, T1>, codec1: Codec<T1>): Codec<V> {
	return RecordCodecBuilder.create {
		it.group(
			codec1.fieldOf(field1.name).forGetter(field1::get)
		).apply(it, factory)
	}
}

fun <V, T1, T2> simpleCodec(factory: (T1, T2) -> V, field1: KProperty1<V, T1>, codec1: Codec<T1>, field2: KProperty1<V, T2>, codec2: Codec<T2>): Codec<V> {
	return RecordCodecBuilder.create {
		it.group(
			codec1.fieldOf(field1.name).forGetter(field1::get),
			codec2.fieldOf(field2.name).forGetter(field2::get),
		).apply(it, factory)
	}
}

fun <V, T1, T2, T3> simpleCodec(factory: (T1, T2, T3) -> V, field1: KProperty1<V, T1>, codec1: Codec<T1>, field2: KProperty1<V, T2>, codec2: Codec<T2>, field3: KProperty1<V, T3>, codec3: Codec<T3>): Codec<V> {
	return RecordCodecBuilder.create {
		it.group(
			codec1.fieldOf(field1.name).forGetter(field1::get),
			codec2.fieldOf(field2.name).forGetter(field2::get),
			codec3.fieldOf(field3.name).forGetter(field3::get),
		).apply(it, factory)
	}
}
