package ru.dbotthepony.mc.otm.android.feature

import net.minecraft.nbt.CompoundTag
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraftforge.event.entity.living.LivingHurtEvent
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.android.AndroidFeature
import ru.dbotthepony.mc.otm.android.AndroidResearchManager
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.energy.extractEnergyExact
import ru.dbotthepony.mc.otm.core.isBypassArmor
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import ru.dbotthepony.mc.otm.registry.StatNames
import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.onceServer
import ru.dbotthepony.mc.otm.triggers.NanobotsArmorTrigger
import kotlin.math.roundToInt

class NanobotsArmorFeature(android: MatteryPlayerCapability) : AndroidFeature(AndroidFeatures.NANOBOTS_ARMOR, android) {
	var strength by synchronizer.int(
		setter = setter@{
				value, access, _ -> access.write(value.coerceIn(0 .. 3))
		}
	).property

	var speed: Int = 0
		set(value) { field = value.coerceIn(0 .. 3) }

	private var ticksPassed = 0
	var layers by synchronizer.int().property

	override fun tickServer() {
		if (layers < strength + 1 && android.androidEnergy.extractEnergyExact(ENERGY_PER_LAYER, true)) {
			ticksPassed++

			if (ticksPassed >= TICKS[speed]) {
				layers++
				android.androidEnergy.extractEnergy(ENERGY_PER_LAYER, false)
				ticksPassed = 0
			}
		} else {
			ticksPassed = 0
		}
	}

	override fun onHurt(event: LivingHurtEvent) {
		ticksPassed = 0

		if (!event.source.isBypassArmor && layers > 0) {
			val absorbed = event.amount * STRENGTH[layers - 1]

			if (absorbed > 0.1f) {
				val powerRequired = ENERGY_PER_HITPOINT * absorbed
				val powerExtracted = android.androidEnergy.extractEnergy(powerRequired, false)
				val realAbsorbed = (powerExtracted / ENERGY_PER_HITPOINT).toFloat()

				val ply = ply

				if (ply is ServerPlayer) {
					onceServer {
						if (!ply.hasDisconnected() && ply.isAlive)
							NanobotsArmorTrigger.trigger(ply, realAbsorbed.toDouble())
					}
				}

				event.amount = event.amount - realAbsorbed
				(ply as ServerPlayer?)?.awardStat(StatNames.DAMAGE_ABSORBED, (realAbsorbed * 10f).roundToInt())
				layers--
			}
		}
	}

	override fun serializeNBT(): CompoundTag {
		return super.serializeNBT().also {
			it["ticksPassed"] = ticksPassed
			it["layers"] = layers
			it["strength"] = strength
			it["speed"] = speed
		}
	}

	override fun deserializeNBT(nbt: CompoundTag) {
		super.deserializeNBT(nbt)
		ticksPassed = nbt.getInt("ticksPassed")
		layers = nbt.getInt("layers")
		strength = nbt.getInt("strength")
		speed = nbt.getInt("speed")
	}

	companion object {
		private val ENERGY_PER_LAYER = Decimal(200)
		private val ENERGY_PER_HITPOINT = Decimal(500)

		private val TICKS = intArrayOf(
			80, // 4 seconds to build a layer
			70, // 3.5 seconds to build a layer
			60, // 3 seconds to build a layer
			50, // 2.5 seconds to build a layer
		)

		private val STRENGTH = floatArrayOf(
			0.15f,
			0.3f,
			0.45f,
			0.6f,
		)
	}
}
