using System.Collections;
using System.Collections.Generic;
using UnityStandardAssets.CrossPlatformInput;
using UnityEngine;
using UnityEngine.UI;
using ninja;
using System.Linq;

public class PlayerSystem : MonoBehaviour {

	public struct PlayerColorInfo {
		public Color color;
		public AudioClip sound;
	}
	class PlayerInfo {
		public int id;
		public PlayerColorInfo color;
		public GameObject entity;
		public Text text;
		public bool ready;
	}

	[SerializeField] private float m_MaxGameTime = 120f;
	[SerializeField] private float m_StartCountDown = 5f;
	[SerializeField] private float m_RestartCountDown = 5f;
	[SerializeField] private int m_maxPlayers = 8;
	public GameObject m_PlayerPrefab;
	public Text m_Text;
	[SerializeField] public Color[] m_PlayerColors;
	[SerializeField] public AudioClip[] m_PlayerColorSounds;
	public AudioClip m_CountdownSound;
	public AudioClip m_WinnerSound;
	public AudioClip m_TitleSound;
	public AudioClip m_TimeUpSound;

	private List<Vector3> m_SpawnPoints = new List<Vector3>();
	private Spawner m_Spawner;
	private List<GameObject> m_Huds = new List<GameObject>();

	private bool m_FirstUpdate = true;
	private bool m_GameRunning = false;
	private bool m_GameOver = false;
	private bool m_StartCountdownRunning;
	private float m_StartCountDownLeft;
	private float m_GameTime;
	private PlayerInfo m_Winner;

	public List<PlayerColorInfo> m_FreePlayerColors = new List<PlayerColorInfo>();
	private List<int> m_FreePlayers = new List<int>();
	private List<PlayerInfo> m_JoinedPlayers = new List<PlayerInfo>();
	private List<Behaviour> m_EnableOnStart = new List<Behaviour>();

	// Use this for initialization
	void Start () {
		for (int i = 0; i < m_PlayerColors.Count (); i++) {
			var c = new PlayerColorInfo ();
			c.color = m_PlayerColors [i];
			c.sound = m_PlayerColorSounds [i];
			m_FreePlayerColors.Add (c);
		}
		Util.Shuffle (m_FreePlayerColors);

		for (int i = 0; i < m_maxPlayers; i++) {
			m_FreePlayers.Add (i);
		}

		foreach (var sp in GameObject.FindGameObjectsWithTag ("SpawnPoint")) {
			m_SpawnPoints.Add (sp.transform.position);
		}
		Util.Shuffle (m_SpawnPoints);

		m_GameTime = m_MaxGameTime;
		m_Spawner = Util.Find<Spawner>("Spawner");

		for(int i=1; i<=4; i++)
			m_Huds.Add (GameObject.Find ("HUD_P"+i));

		foreach (var hud in m_Huds) {
			hud.transform.parent.gameObject.SetActive (false);
			hud.SetActive (false);
		}

	}

	// Update is called once per frame
	void Update () {
		if (m_FirstUpdate) {
			m_FirstUpdate = false;
			GetComponent<AudioSource> ().PlayOneShot(m_TitleSound, 1f);
		}

		if (!m_GameRunning) { // join phase
			foreach (var player in m_JoinedPlayers) {
				m_FreePlayers.Remove (player.id);
				if (!player.ready && CrossPlatformInputManager.GetButtonDown ("P" + (player.id + 1) + "_do")) {
					var p = player;
					p.ready = true;
					p.text.text = "Ready";
				}
			}

			if (m_SpawnPoints.Count > 0) {
				foreach (var pid in m_FreePlayers) {
					if (AnyInputFromPlayer (pid)) {
						JoinPlayer (pid);
					}
				}
			}


			if (m_JoinedPlayers.Count > 0 && m_JoinedPlayers.All(p => p.ready)) {
				if (!m_StartCountdownRunning) {
					m_StartCountdownRunning = true;
					m_StartCountDownLeft = m_StartCountDown;
					GetComponent<AudioSource> ().PlayOneShot (m_CountdownSound, 5f);
				}
			} else if(m_StartCountdownRunning) {
				m_StartCountdownRunning = false;
				GetComponent<AudioSource> ().Stop ();
			}

			if (m_StartCountdownRunning) {
				m_Text.text = "Press A to join!\n\nGame starts in: " + (int)m_StartCountDownLeft;
			} else {
				m_Text.text = "Press A to join!\nPress X to start!";
			}

			if (m_StartCountdownRunning) {
				m_StartCountDownLeft -= Time.deltaTime;
				if (m_StartCountDownLeft <= 0f) {
					GameObject.FindGameObjectWithTag ("MainCamera").GetComponent<AudioSource> ().Play ();
					StartGame ();
				}
			}

		} else {
			m_GameTime -= Time.deltaTime;
			m_Text.text = "" + (int)m_GameTime;

			if (m_GameTime <= 0) {
				m_Text.text = "GAME OVER";

				var audio = GetComponent<AudioSource> ();

				if (!m_GameOver) {
					m_GameOver = true;

					int max_score = 0;
					m_Winner = null;
					foreach (var player in m_JoinedPlayers) {
						var score = player.entity.GetComponent<ScoreCounter> ().GetScore ();
						if (score >= max_score) {
							max_score = score;
							m_Winner = player;
						}
					}

					audio.PlayOneShot (m_TimeUpSound, 4f);
					// TODO: drum roll
					StartCoroutine(playSoundWithDelay(m_WinnerSound, m_TimeUpSound.length));
					StartCoroutine(playSoundWithDelay(m_Winner.color.sound, m_TimeUpSound.length + 1.2f));

					foreach (var player in GameObject.FindGameObjectsWithTag("Player")) {
						player.GetComponent<NinjaMovement> ().enabled = false;
						player.GetComponent<Rigidbody2D> ().simulated = false;
					}
				}

				if (m_GameTime < -m_RestartCountDown) {
					Application.LoadLevel(Application.loadedLevel);
				}
			}
		}
	}

	IEnumerator playSoundWithDelay(AudioClip clip, float delay)
	{
		yield return new WaitForSeconds(delay);
		GetComponent<AudioSource> ().PlayOneShot(clip, 5f);
	}

	private void StartGame() {
		m_GameRunning = true;

		foreach (var c in m_EnableOnStart) {
			c.enabled = true;
		}
	}

	private void JoinPlayer(int id) {
		if (m_SpawnPoints.Count == 0 && m_JoinedPlayers.Count<m_Huds.Count)
			return;
		
		int playerNum = m_JoinedPlayers.Count + 1;

		m_Huds [playerNum - 1].SetActive (true);
		m_Huds [playerNum - 1].transform.parent.gameObject.SetActive (true);

		var position = m_SpawnPoints[m_SpawnPoints.Count-1];
		m_SpawnPoints.RemoveAt (m_SpawnPoints.Count-1);

		var player = Instantiate (m_PlayerPrefab, position, Quaternion.identity);
		var controller = player.GetComponent<NinjaInputController> ();
		m_EnableOnStart.Add (controller);
		controller.SetPlayerId(id);
		controller.enabled = false;

		var score = player.GetComponent<ScoreCounter> ();
		m_EnableOnStart.Add (score);
		score.enabled = false;
		score.m_ScoreText = GameObject.Find ("P" + playerNum + "_score").GetComponent<Text>();
		score.m_TimerText = GameObject.Find ("P" + playerNum + "_time").GetComponent<Text>();

		score.m_ScoreText.text = "Waiting...";

		var color = m_FreePlayerColors [m_FreePlayerColors.Count - 1];
		m_FreePlayerColors.RemoveAt (m_FreePlayerColors.Count - 1);

		score.m_ScoreText.color = color.color;
		score.m_TimerText.color = color.color;

		player.GetComponent<SoundEmitter>().SetColor(color.color);

		var material = player.GetComponent<SpriteRenderer> ().material;
		material.SetColor ("_DestColor", color.color);

		m_Spawner.SpawnSound(position, SoundType.Big, color.color);


		var playerInfo = new PlayerInfo ();
		playerInfo.id = id;
		playerInfo.color = color;
		playerInfo.entity = player;
		playerInfo.text = score.m_ScoreText;
		m_JoinedPlayers.Add (playerInfo);
	}

	private bool AnyInputFromPlayer(int id) {
		return CrossPlatformInputManager.GetButtonDown ("P" + (id + 1) + "_jump") || CrossPlatformInputManager.GetButtonDown ("P" + (id + 1) + "_do");
	}
}
