namespace BP
{
	class AIBot : BP::AI
	{
		array<
		float onFireTime; //[Serialize] time until fire caught on fire effects turn off
		bool isSpawned = false; //[Serialize] was custom spawned
		float deadTimer; //time this AI has been dead
		
		float lastDamage; //last amount of total damage caused
		int damageDisplay; //the damage number to show for popup text
		bool stopDamageLoop; //prevents an infinite loop of inflicting damage on self in the OnDamage callback
		float damageTime; //amount of time until damage popup will go away
		bool showDamagePopup; //need this for particle spawn reasons to show damage OnTick instead of in OnDamage
		WorldText damageText;
		kActor@ movePoint; //a custom point to move to. Null if not moving to custom point
		kActor@ attackPoint; //a custom point to attack. Null if not attacking a custom point
		//------------------------------------------------------------------------------------------------------------------------
		AIBot(kActor @actor)
		{
			super(@actor);
		}
		//------------------------------------------------------------------------------------------------------------------------
		// Called on AI that is in the map data not ones created with ActorFactory
		//------------------------------------------------------------------------------------------------------------------------
		void BP_OnSpawn(void) override
		{
			//self.Health() = 4000;
		}
		//------------------------------------------------------------------------------------------------------------------------
		void BP_OnSerialize(kDict dict) override
		{
			SERIALIZE_FLOAT(onFireTime);
			SERIALIZE_BOOL(isSpawned);
		}
		//------------------------------------------------------------------------------------------------------------------------
		void BP_OnDeserialize(kDict& in dict) override
		{
			DESERIALIZE_FLOAT(onFireTime);
			DESERIALIZE_BOOL(isSpawned);
			@movePoint = null;
			@attackPoint = null;
		}
		//------------------------------------------------------------------------------------------------------------------------
		void BP_OnPreDamage(kDamageInfo& in dmgInfo) override
		{
			self.Flags() &= ~AF_NOINFLICTDAMAGE;
			
			kActor @src = dmgInfo.source;
			
			if (!stopDamageLoop)
			{
				bool isSrcPlayer = @src == @BP::LocalPlayer::Actor;
				//if source of damage is from player or an enemy
				if (isSrcPlayer || src.EnemyAIComponent() !is null)
				{
					stopDamageLoop = true;
					kDamageInfo cDamageInfo;
					cDamageInfo.radius = dmgInfo.radius;
					cDamageInfo.flags = dmgInfo.flags;
					@cDamageInfo.inflictor = @dmgInfo.source;
					@cDamageInfo.source = @dmgInfo.target;
					@cDamageInfo.target = @dmgInfo.target; //not even nesscary
					@cDamageInfo.particle = @dmgInfo.particle;
					cDamageInfo.hits = dmgInfo.hits;
					if (isSrcPlayer)
					{
						cDamageInfo.hits *= BP::LocalPlayer::Script.damage;
					}
					
					self.InflictDamage(cDamageInfo); //calls on predamage then (ondeath and then) ondamage with this new damage
					self.Flags() |= AF_NOINFLICTDAMAGE; //do not call ondeath or ondamage
					
					return;
				}
			}
			else
			{
				//take damage with our new kDamageInfo that we set
				stopDamageLoop = false;
			}
		}
		//------------------------------------------------------------------------------------------------------------------------
		void BP_OnDamage(kDamageInfo& in dmgInfo) override
		{
			// DebugLog("AI Hurt for " + dmgInfo.hits);
			
			kActor @src = dmgInfo.source;
			
			//Setup Damage Popup
			float damage = dmgInfo.hits;
			if (damageTime > 0.0f)
			{
				damage = lastDamage + damage;
			}
			lastDamage = damage;
			damageTime = AI_DAMAGE_TIME;
			damageDisplay = (damage > 0.0f && damage < 1.0f) ? Math::CeilToInt(damage) : int(damage);
			showDamagePopup = true;
			
			//Check if damaged with fire effect
			if (@src != null)
			{
				bool hasFlameEffect;
				kDictMem @def = src.Definition();
				if (@def != null)
				{
					def.GetBool("BP_FlameEffect", hasFlameEffect);
					if (hasFlameEffect)
					{
						onFireTime = 4.0f;
					}
				}
			}
		}
		//------------------------------------------------------------------------------------------------------------------------
		void BP_OnDeath(kDamageInfo& in dmgInfo) override
		{
			//if killed by player
			if (@dmgInfo.inflictor == @BP::LocalPlayer::Actor)
			{
				BP::LocalPlayer::Script.OnAIKIll(@self, dmgInfo);
			}
		}
		//------------------------------------------------------------------------------------------------------------------------
	    void BP_OnTrigger(kActor@ pInstigator, const int msg) override
		{
			switch (self.TriggerMessageID())
			{
				case TRIGGER_MSG_SPAWN:
				{
					isSpawned = true;
					break;
				}
				case TRIGGER_MSG_AI_MOVE_POINT:
				{
					kVec3 point = BP::Trigger::argVectors[0];
					MoveToPoint(point);
					break;
				}
				case TRIGGER_MSG_AI_ATTACK_POINT:
				{
					kVec3 point = BP::Trigger::argVectors[0];
					AttackPoint(point);
					break;
				}
			}
		}
		//------------------------------------------------------------------------------------------------------------------------
		void MoveToPoint(const kVec3&in point)
		{
			if (BP::Actor::Exists(@movePoint))
			{
				movePoint.WorldComponent().SetNearestPosition(point);
			}
			else
			{
				@movePoint = BP::Spawn::Actor(kActor_WayPoint, point);
				movePoint.SetTarget(@self);
			}
			BP::Actor::AIMoveToTarget(@self, @movePoint);
		}
		//------------------------------------------------------------------------------------------------------------------------
		void AttackPoint(const kVec3&in point)
		{
			if (BP::Actor::Exists(@attackPoint))
			{
				attackPoint.WorldComponent().SetNearestPosition(point);
			}
			else
			{
				@attackPoint = BP::Spawn::Actor(kActor_WayPoint, point);
				attackPoint.SetTarget(@self);
			}
			BP::Actor::AIAttackTarget(@self, @attackPoint);
		}
		//------------------------------------------------------------------------------------------------------------------------
		void BP_OnTick() override
		{
			// if (!BP::Actor::IsDead(@self))
			// {
				
			// }
			
			if (showDamagePopup)
			{
				showDamagePopup = false;
				damageText.Show(@self, "" + damageDisplay);
			}
			
			if (onFireTime > 0.0f)
			{
				onFireTime -= GAME_DELTA_TIME;
				self.RenderMeshComponent().ToggleHotPoint(1, true);
			}
			
			if (damageTime > 0.0f)
			{
				damageTime -= GAME_DELTA_TIME;
			}
		}
		//------------------------------------------------------------------------------------------------------------------------
	};
}
