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

public class RobotMonitor : MonoBehaviour
{
	public enum GameState
	{
		Assemble,
		RaceTime,
		Interim
	}
	public GameState state;
	[System.Serializable]
	public class PartSet
	{
		public List<DragAndDropPart> Parts;
		public RobotRoot Body;
	}
	public List<RobotRoot> ValidRoots;
	public List<DragAndDropPart> ValidParts;
	public List<DragAndDropPart> ValidHeadParts;
	public PartSet ActiveSet;
	public UnityEngine.UI.Button ResetButton, RaceButton;
	public Transform PartsBox;

	public TMPro.TextMeshProUGUI ScoreText, BestTravelDistanceText, TravelDistanceText;
	int FixedRobots;

	public Transform Camera;
	public float CameraFollowSpeed = 3;
	float TimeRaceStarted = 0;
	public Transform RaceStartPosition;
	public float CurrentDistance, FurthestDistance;

	List<Vector2> AverageVelocityCalc;

	// Start is called before the first frame update
	void Start()
	{
		InvokeRepeating("UpdateUI", 1f, .1f);
		Invoke("ResetParts", 0.1f);
		AverageVelocityCalc = new List<Vector2>();
	}

	// Update is called once per frame
	void Update()
	{
		switch (state)
		{
			case GameState.Assemble:
				{
					bool CompletedSet = true;
					foreach (var x in ActiveSet.Parts)
					{
						if (!x.Attached)
						{
							CompletedSet = false;
							break;
						}
					}

					if (CompletedSet)
					{
						ActiveSet.Body.GetComponent<Rigidbody2D>().isKinematic = false;
					}


					if (Input.GetMouseButtonDown(1))
					{
						ResetParts();
					}
				}
				break;
			case GameState.RaceTime:
				{
					Camera.position = Vector3.MoveTowards(Camera.position, ActiveSet.Body.transform.position + Vector3.forward * -10, CameraFollowSpeed * Time.deltaTime);

					CurrentDistance = (ActiveSet.Body.transform.position - RaceStartPosition.position).magnitude;
					if(AverageVelocityCalc.Count>200)
						AverageVelocityCalc.RemoveAt(0);
					AverageVelocityCalc.Add(ActiveSet.Body.rigidbody2D.velocity);
					Vector2 AvVelocity = AverageVelocityCalc[0];
					foreach (var v in AverageVelocityCalc)
					{ AvVelocity += v; }
					AvVelocity /= AverageVelocityCalc.Count;
					if (AvVelocity.magnitude < .015f && Time.timeSinceLevelLoad - TimeRaceStarted > 8)
					{
						GiveUp();
					}
				}
				break;

		}
	}
	public void GiveUp()
	{
		StartCoroutine(GenerateNext());
	}
	void UpdateUI()
	{
		if (FurthestDistance < CurrentDistance)
			FurthestDistance = CurrentDistance;
		TravelDistanceText.text = "Travel Distance: " + CurrentDistance;
		BestTravelDistanceText.text = "Best Travel Distance: " + FurthestDistance;
	}
	public void RaceTime()
	{
		if (state == GameState.RaceTime)
		{ GiveUp(); return; }
		bool CompletedSet = true;
		foreach (var x in ActiveSet.Parts)
		{
			if (!x.Attached)
			{
				CompletedSet = false;
				break;
			}
		}

		if (CompletedSet)
		{
			ActiveSet.Body.transform.position = RaceStartPosition.position;
			ActiveSet.Body.transform.rotation = RaceStartPosition.rotation;
			if (ActiveSet.Body.GetComponent<DragAndDropPart>())
				ActiveSet.Body.GetComponent<DragAndDropPart>().StartMotor();
			TimeRaceStarted = Time.timeSinceLevelLoad;
			state = GameState.RaceTime;
			RaceButton.GetComponentInChildren<TMPro.TextMeshProUGUI>().text = "Give Up :(";

			#if UNITY_EDITOR
				if (UnityEditor.Selection.gameObjects.Length < 1)
					UnityEditor.Selection.activeGameObject = ActiveSet.Body.gameObject;
			#endif

			foreach (var x in ActiveSet.Parts)
			{
				x.StartMotor();
				x.transform.position = RaceStartPosition.position;
			}
		}
	}
	IEnumerator GenerateNext()
	{
		state = GameState.Interim;

		foreach (var x in ActiveSet.Parts)
		{
			Destroy(x.gameObject, 5);
			x.StartMotor();
		}
		Destroy(ActiveSet.Body.gameObject, 5);
		ActiveSet.Body.rigidbody2D.isKinematic = true;
		ActiveSet = null;
		yield return new WaitForSeconds(5);
		FixedRobots++;
		ScoreText.text = "Completed Robots: " + FixedRobots;
		ActiveSet = new PartSet
		{
			Body = Instantiate(ValidRoots[Random.Range(0, ValidRoots.Count)]),
			Parts = new List<DragAndDropPart>()
		};
		ActiveSet.Body.GetComponent<Rigidbody2D>().isKinematic = true;
		for (int i = 0; i < Random.Range(ActiveSet.Body.AttachPoints.Count-1, ActiveSet.Body.AttachPoints.Count * 2); ++i)
		{
			ActiveSet.Parts.Add(Instantiate(ValidParts[Random.Range(0, ValidParts.Count)], PartsBox.position, PartsBox.rotation));
			if (ActiveSet.Parts[i].GetComponentsInChildren<DragAndDropPart>().Length > 1)
			{
				ActiveSet.Parts.Add(ActiveSet.Parts[i].GetComponentsInChildren<DragAndDropPart>()[1]);
			}
		}
		for (int i = 0; i < Random.Range(1, 2); ++i)
			ActiveSet.Parts.Add(Instantiate(ValidHeadParts[Random.Range(0, ValidHeadParts.Count)], PartsBox.position, PartsBox.rotation));
		state = GameState.Assemble;
		Camera.transform.position = new Vector3(0, 0, -10);
		CurrentDistance = 0;

		RaceButton.GetComponentInChildren<TMPro.TextMeshProUGUI>().text = "Race!";
	}

	public void ResetParts()
	{
		switch (state)
		{
			case GameState.Assemble:
				foreach (var x in ActiveSet.Parts)
				{
					x.transform.position = PartsBox.position;
					x.transform.rotation = PartsBox.rotation;
					x.Detach();
					x.GetComponent<Rigidbody2D>().velocity = new Vector2();
				}
				ActiveSet.Body.rigidbody2D.velocity = new Vector2();
				ActiveSet.Body.rigidbody2D.isKinematic = true;
				ActiveSet.Body.transform.position = new Vector3();
				if (ActiveSet.Body.GetComponent<DragAndDropPart>())
				{
					ActiveSet.Body.GetComponent<DragAndDropPart>().Detach();
					ActiveSet.Body.rigidbody2D.isKinematic = false;
				}
				break;
			case GameState.RaceTime:
				ActiveSet.Body.transform.position = RaceStartPosition.position;
				ActiveSet.Body.transform.rotation = RaceStartPosition.rotation;
				TimeRaceStarted = Time.timeSinceLevelLoad;
				state = GameState.RaceTime;
				break;
		}
	}
}
