#include "component_control_redirect.h"

/* DEPENDENCIES: Physics, Redirect, Return */

static bool _component_control_redirect_reset_check(ComponentControlRedirect* self, ECS* ecs);
static void _component_control_redirect(ComponentControlRedirect* self, ECS* ecs);

static void
_redirect_arrow_update(ComponentControlRedirect* self, ECS* ecs)
{
	ComponentRedirects* redirects;
	vec3 mousePosition;
	u32 previousID;
	bool isDisabled;

	mouse_world_position_get(&ecs->game->input.mouse, &ecs->game->renderer, mousePosition);
	redirects = ecs_component_get(ecs, ECS_COMPONENT_REDIRECTS, self->component.id);

	previousID = self->redirectArrowID;

	isDisabled = false;

	if (self->isRedirectArrow)
	{
		ComponentActionFollow* actionFollow;
		ComponentActionLock* actionLock;
		ComponentActionReturn* actionReturn;
		ComponentSprite* sprite;


		actionFollow = ecs_component_get(ecs, ECS_COMPONENT_ACTION_FOLLOW, self->redirectArrowID);

		if 
		(
		 	!actionFollow ||
			redirects->isOut 
		)
		{
			ecs_entity_delete(ecs, self->redirectArrowID);
			self->isRedirectArrow = false;
			return;
		}

		sprite = ecs_component_get(ecs, ECS_COMPONENT_SPRITE, self->redirectArrowID);
		actionLock = ecs_component_get(ecs, ECS_COMPONENT_ACTION_LOCK, actionFollow->followID);
		actionReturn = ecs_component_get(ecs, ECS_COMPONENT_ACTION_RETURN, actionFollow->followID);

		if 
		(
			(actionLock && actionLock->isLocked) ||
			(actionReturn && actionReturn->isReturning)
		)
		{
			sprite->color[3] = 0.0f;	
			isDisabled = true;
		}

	}

	/* Do we have projectiles out and about? */
	if (ecs->lists[ECS_COMPONENT_ACTION_REDIRECT].components.count == 0)
		return;

	if (redirects->isOut)
		return;

	for (s32 i = 0; i < (s32)ecs->lists[ECS_COMPONENT_ACTION_REDIRECT].components.count; i++)
	{
		ComponentActionRedirect* actionRedirect;
		ComponentActionReturn* actionReturn;

		actionRedirect = ecs_component_from_index_get(ecs, ECS_COMPONENT_ACTION_REDIRECT, i);
		actionReturn = ecs_component_from_index_get(ecs, ECS_COMPONENT_ACTION_RETURN, i);

		if 
		(
			actionRedirect->sender == self->component.id &&
			!actionReturn->isReturning
		)
		{
			ComponentSprite* sprite;
			ComponentSprite* arrowSprite;
			ComponentActionFollow* actionFollow;
			ComponentPhysics* physics;
			f32 angleDifference;
			f32 prospectiveAngle;

			physics = ecs_component_get(ecs, ECS_COMPONENT_PHYSICS, actionRedirect->component.id);
			sprite = ecs_component_get(ecs, ECS_COMPONENT_SPRITE, actionRedirect->component.id);

			if (!self->isRedirectArrow)
			{
				self->redirectArrowID = ecs_entity_add(ecs);

				entity_redirect_arrow_init
				(
					ecs,
					self->redirectArrowID,
					sprite->position,
					actionRedirect->component.id
				);

				self->isRedirectArrow = true;
			}

			if (previousID == self->redirectArrowID && isDisabled)
				return;

			arrowSprite = ecs_component_get(ecs, ECS_COMPONENT_SPRITE, self->redirectArrowID);

			arrowSprite->color[3] = 1.0f;

			actionFollow = ecs_component_get(ecs, ECS_COMPONENT_ACTION_FOLLOW, self->redirectArrowID); 

			prospectiveAngle = ATAN
			(
				mousePosition[0],
				physics->position[0],
				mousePosition[1],
				physics->position[1]
			);

			angleDifference = fabs(physics->angle - prospectiveAngle);

			if (angleDifference < self->angleThreshold)
			{
				arrowSprite->color[3] = 0.25f;
				continue;
			}

			actionFollow->followID = actionRedirect->component.id;
		}
	}


}

/* Determines if you get your redirects back. */
static bool
_component_control_redirect_reset_check(ComponentControlRedirect* self, ECS* ecs)
{
	for (s32 i = 0; i < (s32)ecs->lists[ECS_COMPONENT_ACTION_REDIRECT].components.count; i++)
	{
		ComponentActionRedirect* actionRedirect;
	
		actionRedirect = vector_get(&ecs->lists[ECS_COMPONENT_ACTION_REDIRECT].components, i);

		if (actionRedirect->sender == self->component.id)
			return false;
	}

	return true;
}

/* Find all projectiles that can be redirected. */
/* The first valid one will be redirected. */
/* Valid ones are the ones closest to you and with a different enough angle. */
static void
_component_control_redirect(ComponentControlRedirect* self, ECS* ecs)
{
	ComponentRedirects* redirects;
	vec3 mousePosition;
	bool isSuccess;
	bool isUnlockedProjectileRedirected;

	isSuccess = false;
	isUnlockedProjectileRedirected = false;

	redirects = ecs_component_get(ecs, ECS_COMPONENT_REDIRECTS, self->component.id);

	mouse_world_position_get(&ecs->game->input.mouse, &ecs->game->renderer, mousePosition);

	for (s32 i = 0; i < (s32)ecs->lists[ECS_COMPONENT_ACTION_REDIRECT].components.count; i++)
	{
		ComponentActionRedirect* actionRedirect;
		ComponentPhysics* physics;
		ComponentActionReturn* actionReturn;
		ComponentActionLock* actionLock;
	
		actionRedirect = ecs_component_from_index_get(ecs, ECS_COMPONENT_ACTION_REDIRECT, i);

		actionReturn = ecs_component_get(ecs, ECS_COMPONENT_ACTION_RETURN, actionRedirect->component.id);
		actionLock = ecs_component_get(ecs, ECS_COMPONENT_ACTION_LOCK, actionRedirect->component.id);
		physics = ecs_component_get(ecs, ECS_COMPONENT_PHYSICS, actionRedirect->component.id);

		if 
		(
			actionRedirect->sender == self->component.id &&
			!actionReturn->isReturning
		)
		{
			f32 prospectiveAngle;
			f32 angleDifference;

			/* Redirect all aimed locked projectiles. */
			if (actionLock->isRedirectAngleGiven)
			{
				isSuccess = true;
				component_action_lock_unlock(actionLock, ecs);
				physics->angle = actionLock->angle;
				actionRedirect->isRedirect = true;
				actionLock->isLock = false;
				actionRedirect->isGivenAngle = true;
			}

			if (actionLock->isLock)
				continue;

			/* But only redirect one non-locked projectile. */
			if (isUnlockedProjectileRedirected)
				continue;

			/* And check if their angle is different enough. */
			prospectiveAngle = ATAN
			(
				mousePosition[0],
				physics->position[0],
				mousePosition[1],
				physics->position[1]
			);

			angleDifference = fabs(physics->angle - prospectiveAngle);

			if (angleDifference < self->angleThreshold)
				continue;

			/* If all of that shit is gucci, you can redirect the damn projectile. */

			isSuccess = true;
			actionRedirect->isRedirect = true;
			isUnlockedProjectileRedirected = true;
		}

	}

	if (isSuccess)
		redirects->value--;
}

/* Initialize control redirect component. */
/* NOTE: converted to radians, so use degrees */
void
component_control_redirect_init(ComponentControlRedirect* self, f32 angleThreshold)
{
	self->angleThreshold = RADIANS(angleThreshold);
}

/* Ticks control redirect.. */
void
component_control_redirect_tick(ComponentControlRedirect* self, ECS* ecs)
{
	ComponentRedirects* redirects;

	redirects = ecs_component_get(ecs, ECS_COMPONENT_REDIRECTS, self->component.id);

	/* Determine if there's no more projectiles of yours on the field. If there's none,
	 * you get your redirects back. */
	if (_component_control_redirect_reset_check(self, ecs))
	{
		redirects->value = redirects->max;
		redirects->isOut = false;
	}

	if (input_press(&ecs->game->input, INPUT_REDIRECT) && !redirects->isOut)
		_component_control_redirect(self, ecs);

	_redirect_arrow_update(self, ecs);
}
