using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;

public class BallManager : SceneSingleton<BallManager> {

	[SerializeField]
	float strength;

	[SerializeField]
	public Ball activeBall;
	
	BallDefinition activeBallDefinition;

	[SerializeField]
	SpriteRenderer ballSpriteRenderer;
	
	[SerializeField]
	BallDefinition[] ballDefinitions;

	[SerializeField]
	Text newText;

	public delegate void InGameAction();

	public static InGameAction onEndOfGame; 
	public static InGameAction onTap;

	const float BOTTOM_VALUE_WITH_MARGIN = -10.12f;

	[SerializeField]
	float minimumBallSize;

	[SerializeField]
	float maximumBallSize;

	[SerializeField]
	Vector2 startingPos;

	[SerializeField]
	TeleportComponent teleport;

	bool decoyPrepared;

	[SerializeField]
	Ball decoyPrefab;

	void Start()
	{
		Color colour = Color.white;
		ChangeBall();
		ResetGame();
		//decoyPrepared = true;
	}

	void ResetGame()
	{

		activeBall.transform.position = startingPos;
		activeBall.rigidbody2D.isKinematic = true;
		ScoreManager.Instance.Reset();
	}

	void ActivateRigidbody()
	{
		activeBall.rigidbody2D.isKinematic = false;
		//Rotate();
	}

	public void MoveActiveBall(Vector2 position)
	{

		if(onTap != null)
		{
			onTap();
		}

		ScoreManager.Instance.OnBallHit();

		ActivateRigidbody();

		Color newBallColour;

		Collider2D collider = ChangeBall();
		
		activeBall.OnHit(position, strength);

		if(decoyPrepared)
		{
			MakeDecoy(collider);
		}

		//decoyPrepared = !decoyPrepared;

	}

	void MakeDecoy(Collider2D ballCollider)
	{
		Ball decoy = (Ball) Instantiate( decoyPrefab, activeBall.transform.position, activeBall.transform.rotation);
		decoy.rigidbody2D.angularVelocity = activeBall.rigidbody2D.angularVelocity;
		//decoy.rigidbody2D.velocity = activeBall.rigidbody2D.velocity;
		decoy.rigidbody2D.AddForceAtPosition(Vector2.up * strength , activeBall.transform.position, ForceMode2D.Impulse);

		int randomElement = Random.Range(0, ballDefinitions.Length);
		//Physics2D.IgnoreCollision(, BallManager.Instance.activeBall.GetComponentInChildren<Collider2D>());
		decoy.GetComponent<SpriteRenderer>().sprite = ballDefinitions[randomElement].sprite;
		decoy.SetAlphaMaterial(ballDefinitions[randomElement].alphaSprite.texture);
		decoy.ScaleBall(minimumBallSize, maximumBallSize);
		decoy.SetColor(activeBall.GetComponent<SpriteRenderer>().color);
		decoy.SetFaceSprite(activeBall.GetFaceSprite());
		Collider2D decoyCollider = decoy.ChangeCollider(ballDefinitions[randomElement].colliderName);
		Physics2D.IgnoreCollision(ballCollider, decoyCollider, true);
		decoyPrepared = false;
	}

	[RPC]
	void ChangeMass(float massChange)
	{
		newText.text = "Mass Changed";
		MassStatAddOn massStatAddOn = activeBall.gameObject.AddComponent<MassStatAddOn>();
		massStatAddOn.tapsLeft = AddOnStats.MASS_CHANGE_TAPS_PERIOD;
		massStatAddOn.extraValue = massChange;
		activeBall.baseStatAddOns.Add(massStatAddOn);
	}

	[RPC]
	void ChangeGravity(float additionalGravityToAdd)
	{
		newText.text = "Gravity Changed";
		GravityStatAddOn gravityStatAddOn = activeBall.gameObject.AddComponent<GravityStatAddOn>();
		gravityStatAddOn.tapsLeft = AddOnStats.GRAVITY_CHANGE_TAPS_PERIOD;
		gravityStatAddOn.extraValue = additionalGravityToAdd;
		activeBall.baseStatAddOns.Add(gravityStatAddOn);
	}

	[RPC]
	void BlindPlayer()
	{
		newText.text = "Blind Command Received";
		BlindStatAddOn blindStatAddOn = activeBall.gameObject.AddComponent<BlindStatAddOn>();
		blindStatAddOn.tapsLeft = AddOnStats.BLIND_TAPS_PERIOD;
		activeBall.baseStatAddOns.Add(blindStatAddOn);
	}
	
	[RPC]
	void ChangeShape()
	{
		newText.text = "Change Shape Command Received";
		Color colour;
		ChangeBall();
		// ChangeShape
	}

	[RPC]
	void ActivateDecoy()
	{
		newText.text = "Decoy Command Received";
		decoyPrepared = true;
		// Duplicate existing shape and mark it as a decoy
	}
	
	[RPC]
	void ChangeFlight()
	{
		newText.text = "Change Flight Command Received";
		float randomX = Random.Range(AddOnStats.MINIMUM_FLIGHT_CHANGE_X_DIRECTION, AddOnStats.MAXIMUM_FLIGHT_CHANGE_X_DIRECTION);
		float remainingY = 1 - randomX;
		if(Random.Range(0, 2) == 0)
		{
			randomX = -randomX; 
		}

		activeBall.MoveBallInDirection(new Vector2(randomX, remainingY), activeBall.transform.position, 
		                               Random.Range(AddOnStats.MINIMUM_FLIGHT_CHANGE_STRENGTH, AddOnStats.MAXIMUM_FLIGHT_CHANGE_STRENGTH));
	}

	[RPC]
	void Teleport()
	{
		// The ball moves to a new spot.
		teleport.Teleport(activeBall.transform);

	}

	[RPC]
	void Rotate()
	{
		activeBall.RotateBall(AddOnStats.AMOUNT_OF_TORQUE_TO_ADD);
	}

	Collider2D ChangeBall()
	{

		List<BallDefinition> ballsToChooseFrom = new List<BallDefinition>();
		ballsToChooseFrom.AddRange(ballDefinitions);
		if(activeBallDefinition != null)
		{
			ballsToChooseFrom.Remove(activeBallDefinition);
			//activeBallDefinition.collider.gameObject.SetActive(false);
		}

		int randomElement = Random.Range(0, ballsToChooseFrom.Count);

		//ballSpriteRenderer.sprite = ballsToChooseFrom[randomElement].sprite;
		//ballsToChooseFrom[randomElement].collider.gameObject.SetActive(true);
		activeBallDefinition = ballsToChooseFrom[randomElement];

		activeBall.MoveFace(activeBallDefinition.faceOffset);

		activeBall.ScaleBall(minimumBallSize, maximumBallSize);

		activeBall.SetAlphaMaterial(activeBallDefinition.alphaSprite.texture);

		activeBall.SetSprite(ballsToChooseFrom[randomElement].sprite);

		//colour = activeBall.ChooseColor();
		// So we now need to keep the face the same size.
		return activeBall.ChangeCollider(ballsToChooseFrom[randomElement].colliderName);
	}

	void Update()
	{
		if(activeBall.transform.position.y < BOTTOM_VALUE_WITH_MARGIN)
		{
			activeBall.ChooseColor();
			activeBall.ChangeFace();

			if(onEndOfGame != null)
			{
				onEndOfGame();

			}
			ResetGame();
		}
	}

	[RPC]
	void SendTap()
	{

	}

	[RPC]
	void SendButtonPress(int index)
	{
		SymbolManager.Instance.EnableSymbolRenderer(index);
	}

}

[System.Serializable]
public class BallDefinition
{
	public Sprite sprite;
	public string colliderName;
	public Vector2 faceOffset;
	public Sprite alphaSprite;
}
