#include "StunBehavior.h"

#include "BaseCombatAIComponent.h"
#include "BehaviorBranchContext.h"
#include "BehaviorContext.h"
#include "EntityManager.h"
#include "Game.h"
#include "dLogger.h"
#include "DestroyableComponent.h"


void StunBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch)
{
	if (this->m_stunCaster || branch.target == context->originator) {
		return;
	}

	bool blocked;
	bitStream->Read(blocked);

	auto* target = EntityManager::Instance()->GetEntity(branch.target);

	if (target == nullptr)
	{
		Game::logger->Log("StunBehavior", "Failed to find target (%llu)!\n", branch.target);

		return;
	}

	/*
	 * If our target is an enemy we can go ahead and stun it.
	 */
	
	auto* combatAiComponent = static_cast<BaseCombatAIComponent*>(target->GetComponent(COMPONENT_TYPE_BASE_COMBAT_AI));

	if (combatAiComponent == nullptr)
	{
		return;
	}

	combatAiComponent->Stun(branch.duration);
}

void StunBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch)
{
	if (this->m_stunCaster || branch.target == context->originator)
	{
		auto* self = EntityManager::Instance()->GetEntity(context->originator);

		if (self == nullptr)
		{
			Game::logger->Log("StunBehavior", "Invalid self entity (%llu)!\n", context->originator);

			return;
		}

		/*
		 * See if we can stun ourselves
		 */
		
		auto* combatAiComponent = static_cast<BaseCombatAIComponent*>(self->GetComponent(COMPONENT_TYPE_BASE_COMBAT_AI));

		if (combatAiComponent == nullptr)
		{
			return;
		}

		combatAiComponent->Stun(branch.duration);
		
		return;
	}

	bool blocked = false;

	auto* target = EntityManager::Instance()->GetEntity(branch.target);

	if (target != nullptr)
	{
		auto* destroyableComponent = target->GetComponent<DestroyableComponent>();

		if (destroyableComponent != nullptr)
		{
			blocked = destroyableComponent->IsKnockbackImmune();
		}
	}

	bitStream->Write(blocked);

	if (target == nullptr)
	{
		Game::logger->Log("StunBehavior", "Failed to find target (%llu)!\n", branch.target);

		return;
	}

	/*
	 * If our target is an enemy we can go ahead and stun it.
	 */

	auto* combatAiComponent = static_cast<BaseCombatAIComponent*>(target->GetComponent(COMPONENT_TYPE_BASE_COMBAT_AI));

	if (combatAiComponent == nullptr)
	{
		return;
	}

	combatAiComponent->Stun(branch.duration);
}

void StunBehavior::Load()
{
	this->m_stunCaster = GetBoolean("stun_caster");
}