using EntityStates;
using EntityStates.ChildMonster;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Serialization;

namespace RoR2;

[RequireComponent(typeof(EntityStateMachine))]
[RequireComponent(typeof(CharacterBody))]
public class ChildMonsterController : MonoBehaviour
{
	public CharacterBody characterBody;

	public EntityStateMachine stateMachine;

	public GameObject tpEffectPrefab;

	[Tooltip("If Child receives this much cumulative damage, they will start trying to teleport.")]
	[FormerlySerializedAs("frolicThreshold")]
	public float cumulativeDamageThresholdBeforeFrolic = 10f;

	[Tooltip("Does not apply to 'falling off cliffs!' teleporting.")]
	public float teleportCooldown = 20f;

	[Tooltip("Which skill slot is 'Frolic' (teleport) categorized as.")]
	public SkillSlot frolicSkillSlot;

	private float inAirTimer;

	public float amountToFallBeforeTp = 1.5f;

	private float cachedYPosition;

	private SkillLocator skillLocator;

	private float lastTeleportTimestamp = -1f;

	private float healthAtLastTeleport;

	private BaseState requestedTeleportState;

	private bool hasAuthority;

	private void Start()
	{
		skillLocator = characterBody.skillLocator;
		cachedYPosition = characterBody.corePosition.y;
		hasAuthority = Util.HasEffectiveAuthority(characterBody.networkIdentity);
		RegisterTeleport(addInvincibility: false);
		lastTeleportTimestamp = -1f;
	}

	private void Update()
	{
		if (characterBody == null || !characterBody.healthComponent.alive)
		{
			return;
		}
		TryRefreshTeleportAbility();
		if (hasAuthority)
		{
			HandleFalling();
			HandleCumulativeDamage();
			if (requestedTeleportState != null)
			{
				SetNextStateToTeleport();
			}
		}
	}

	private void SetNextStateToTeleport()
	{
		if (stateMachine.CanInterruptState(requestedTeleportState.GetMinimumInterruptPriority()))
		{
			stateMachine.SetNextState(requestedTeleportState);
			requestedTeleportState = null;
		}
	}

	private void HandleFalling()
	{
		if (!characterBody.characterMotor.isGrounded && characterBody.corePosition.y < cachedYPosition)
		{
			inAirTimer += Time.deltaTime;
		}
		else
		{
			inAirTimer = 0f;
		}
		cachedYPosition = characterBody.corePosition.y;
		if (inAirTimer > amountToFallBeforeTp)
		{
			inAirTimer = 0f;
			requestedTeleportState = new FrolicAway();
		}
	}

	private void TryRefreshTeleportAbility()
	{
		if (lastTeleportTimestamp != -1f && CheckTeleportAvailable())
		{
			lastTeleportTimestamp = -1f;
		}
	}

	private void HandleCumulativeDamage()
	{
		if (requestedTeleportState == null && CheckTeleportAvailable() && healthAtLastTeleport - characterBody.healthComponent.health >= cumulativeDamageThresholdBeforeFrolic)
		{
			requestedTeleportState = new Frolic();
		}
	}

	public bool CheckTeleportAvailable()
	{
		if (lastTeleportTimestamp != -1f)
		{
			return Time.time - lastTeleportTimestamp >= teleportCooldown;
		}
		return true;
	}

	public void RegisterTeleport(bool addInvincibility = true)
	{
		lastTeleportTimestamp = Time.time;
		healthAtLastTeleport = characterBody.healthComponent.health;
		requestedTeleportState = null;
		skillLocator.GetSkill(frolicSkillSlot)?.DeductStock(100);
		if (addInvincibility && NetworkServer.active && !characterBody.HasBuff(RoR2Content.Buffs.HiddenInvincibility))
		{
			characterBody.AddTimedBuff(RoR2Content.Buffs.HiddenInvincibility, 1.5f);
		}
	}
}
