using UnityEngine;
using UnityEngine.AI;//Use unity ai 
public class EnemyAI : MonoBehaviour
{
	public NavMeshAgent enemyAI;
	public Transform player;
	public LayerMask whatIsGround, whatIsPlayer;
	public GameObject projectile;
	public float health;

	//Enemy patrolling
	public Vector3 patrolPoint;
	public float patrolPointRange;
	bool isPatrolPointSet;

	//Enemy attacking
	public float timeBetweenAttacks;
	bool enemyAttacked;

	//Enemy states
	public float sightRange, attackRange;
	public bool playerIsInSightRange, playerIsInAttackRange;

	private void Start()
	{
		player = GameObject.Find("PlayerMesh").transform;//Find the player's position
		enemyAI = GetComponent<NavMeshAgent>();//Get navmesh agent component of enemy
	}
	private void Update()
	{
		//check if enemy is in the sight and attack range
		playerIsInSightRange = Physics.CheckSphere(transform.position, sightRange, whatIsPlayer);//Create a check sphere to check if player is in sight range
		playerIsInAttackRange = Physics.CheckSphere(transform.position, attackRange, whatIsPlayer);//same as above, excepts check if in attack range

		if (!playerIsInSightRange && !playerIsInAttackRange)//If player isnt in the sight range and attack range of enemy, patrol the area
		{
			Patrolling();//call patrol function
		}
		if (playerIsInSightRange && !playerIsInAttackRange)//if player is in the sight range but not in attack range, chase the player
		{
			ChasePlayer();//call chase function
		}
		if (playerIsInSightRange && playerIsInAttackRange)//If player is in attack and sight range, attack the player
		{
			AttackPlayer();//call attack function
		}
	}

	private void Patrolling()
	{
		if (!isPatrolPointSet)//if there is no patrol perimiter set
		{
			SearchPatrolPoint();//we must search for a patrol point using this function
		}
		if (isPatrolPointSet)//if the patrol perimeter has been set
		{
			enemyAI.SetDestination(patrolPoint);//the enemy will now set its destination to the patrol point and move to it
		}
		Vector3 distanceToPatrolPoint = transform.position - patrolPoint;//calculates distance between enemy and patrol point

		if(distanceToPatrolPoint.magnitude < 1f)//if the distance is less than 1, that means the enemy has reached the patrol point
		{
			isPatrolPointSet = false;//set point set to false, which will cause searchpatrolpoint function to be activated
		}

	}
	private void SearchPatrolPoint()
	{
		float randomZ = Random.Range(-patrolPointRange, patrolPointRange);//Create a random patrol point on z axis for enemy to walk
		float randomX = Random.Range(-patrolPointRange, patrolPointRange);//Create a random patrol point on x axis for enemy to walk

		//Creating a patrol point using random x and z axis values added onto the enemy's current position
		patrolPoint = new Vector3(transform.position.x + randomX, transform.position.y, transform.position.z + randomZ);

		//the patrol point could be outside the map, so we must check it is on the ground by shootinga raycast
		if (Physics.Raycast(patrolPoint, -transform.up, 2f, whatIsGround))
		{
			isPatrolPointSet = true;//the patrol point has been set, so we must set it to true
		}
	}
	private void ChasePlayer()
	{
		enemyAI.SetDestination(player.position);//Enemy will walk towards the player's position
	}
	private void AttackPlayer()
	{
		enemyAI.SetDestination(transform.position);//Enemy will stop moving when attacking
		transform.LookAt(player);//Enemy will look at the player when attacking
		if (!enemyAttacked)//if the enemy has not been attacked
		{
			Rigidbody rb = Instantiate(projectile, transform.position, Quaternion.identity).GetComponent<Rigidbody>();
			rb.AddForce(transform.forward * 32f, ForceMode.Impulse);
			rb.AddForce(transform.up * 2f, ForceMode.Impulse);
			enemyAttacked = true;//set enemy attacked to true
			Invoke(nameof(ResetAttack), timeBetweenAttacks);//invoke the reset attack function after timebetweenattacks variable
		}
	}
	private void ResetAttack()
	{
		enemyAttacked = false;//set enemy attack to false when resetting the attack of the enemy
	}

	public void TakeDamage(int damage)
	{
		health -= damage;

		if (health<= 0)
		{
			Destroy(gameObject);
		}
	}
}