﻿using UnityEngine;

namespace AC.CombatExample
{

	public class Enemy : CombatCharacter
	{

		// The enemy class, which causes a character to chase/attack the Player if within range

		#region Variables

		[SerializeField] private string pauseEnemiesGlobalVariableName = "PauseEnemies";
		private GVar pauseEnemiesVariable;

		[SerializeField] private AudioClip idleSound = null;
		[SerializeField] private AudioClip attackSound = null;
		[SerializeField] private float attackProximity = 1.0f;
		[SerializeField] private float followProximity = 10.0f;
		[SerializeField] private float attackRate = 1.5f;
		[SerializeField] protected float range = 0.5f;
		[SerializeField] protected int damage = 20;

		private Animator _animator = null;
		private NPC npc = null;
		private CharacterController characterController = null;
		private float idleTimer;
		
		#endregion


		#region UnityStandards

		private void Awake ()
		{
			_animator = GetComponent <Animator>();
			npc = GetComponent <NPC>();
			characterController = GetComponent <CharacterController> ();

			originalWalkSpeed = npc.walkSpeedScale;
			originalRunSpeed = npc.runSpeedScale;
			originalTurnSpeed = npc.turnSpeed;

			ResetIdleTimer ();
		}


		private void Update ()
		{
			npc.GetAnimator ().enabled = !PauseEnemies;
			characterController.enabled = Health > 0f && !PauseEnemies;

			if (IsDead () || PauseEnemies)
			{
				return;
			}

			if (!PlayerIsAlive)
			{
				npc.StopFollowing ();
				return;
			}

			// Play an idle sound occasionally
			if (idleTimer > 0f)
			{
				idleTimer -= Time.deltaTime;
				if (idleTimer <= 0f)
				{
					AudioSource.PlayClipAtPoint (idleSound, transform.position);
					ResetIdleTimer ();
				}
			}

			// Follow the Player if close enough
			float playerProximity = Vector3.Distance (transform.position, KickStarter.player.transform.position);
			if (playerProximity > followProximity)
			{
				if (npc.GetFollowTarget ())
				{
					npc.StopFollowing ();
				}
			}
			else
			{
				if (npc.GetFollowTarget () == null)
				{
					npc.FollowAssign (KickStarter.player, true, 2f, 0.1f, 0.1f, true, false, false);
				}
			}

			// Attack the Player if close enough
			if (playerProximity < attackProximity)
			{
				float facingDot = Vector3.Dot (transform.forward, (KickStarter.player.transform.position - transform.position).normalized);
				if (facingDot > 0.7f && CanAttack ())
				{
					Attack ();
				}
			}
		}

		#endregion


		#region ProtectedFunctions

		protected override void OnDie ()
		{
			AudioSource.PlayClipAtPoint (dieSound, transform.position);
			_animator.CrossFadeInFixedTime ("Die", animCrossfadeTime, 0);
			npc.motionControl = MotionControl.Manual;
			characterController.enabled = false;
			npc.StopFollowing ();
		}


		protected override void OnTakeDamage ()
		{
			AudioSource.PlayClipAtPoint (takeDamageSound, transform.position);
			_animator.CrossFadeInFixedTime ("TakeDamage", animCrossfadeTime, 1);
		}

		
		protected override void Attack ()
		{
			AudioSource.PlayClipAtPoint (attackSound, transform.position);
			_animator.CrossFadeInFixedTime ("Attack", animCrossfadeTime, 1);
			SetAttackDelay (attackRate);
			RaycastHit raycastHit;
			if (Physics.SphereCast (npc.transform.position + Vector3.up, 0.35f, npc.transform.forward, out raycastHit, range))
			{
				PlayerCombat _playerCombat = raycastHit.collider.GetComponent<PlayerCombat> ();
				if (_playerCombat)
				{
					_playerCombat.TakeDamage (damage);
				}
			}
		}

		#endregion


		#region PrivateFunctions

		private void ResetIdleTimer ()
		{
			idleTimer = Random.Range (2f, 6f);
		}

		#endregion


		#region GetSet

		private bool PauseEnemies
		{
			get
			{
				if (pauseEnemiesVariable == null) pauseEnemiesVariable = GlobalVariables.GetVariable (pauseEnemiesGlobalVariableName);
				return pauseEnemiesVariable.BooleanValue;
			}
		}


		private bool PlayerIsAlive
		{
			get
			{
				if (PlayerCombat.Instance)
				{
					return !PlayerCombat.Instance.IsDead ();
				}
				return false;
			}
		}

		#endregion

	}

}