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

public enum Direction {Up,Down,Left,Right};

public enum GameState{Playing, GameOver};

public class GameController : MonoBehaviour {

	//public GameObject waveObject; 
	//static public float waveVelocity;
	//static public float waveBounds; 

	private Vector3[] enemySpawnLocations;
	private Vector3 waveShotRotation;
	private Direction spawnDirection;
	private float enemySpawnTime;
	private float spawnTimer;
	private int velocityMulitplier;
	private float challengeTimer;
	private float scoreTimer;
	private GameState gameState;


	//temp
	static public Texture waveTex0;

	//wave textures
	//TODO: in Wave class, add private Texture[] for enemy and player textures
	static public Texture[] playerWaveTex;
	static public Texture[] enemyWaveTex;
	static public Texture[] chargeTex;

	static public float playerWaveCBL;
	static public float[] enemyWaveCBL;

	static public float[] waveLevelOffsetDivider;

	static public AudioClip[] waveShotAudio;
	static public AudioClip[] waveChargeAudio;
	//static public AudioClip chargingAudio;
	static public AudioClip reverdAudio;
	static public AudioClip waveShrinkAudio;
	static public AudioClip waveDestroyAudio;
	static public AudioClip playerHitAudio;
	static public AudioClip gameOverAudio;

	static public GameObject destroyedWave;




	//public GameState gState;

	public GameObject uiText;
	public GameObject player;
	public GameObject[] enemySpawnPoints;
	public GameObject wavePrefab;
	public float enemySpawnRate; //enemies per 20 seconds
	public float spawnVelocity;
	public int challengeLevel;
	public float challengeIncrease;

	private Vector3 waveRotation; //Eular Angle

	// Use this for initialization
	void Awake () {

		playerWaveTex = new Texture[4] {
			Resources.Load<Texture> ("WavePlayer1"),
			Resources.Load<Texture> ("WavePlayer2"),
			Resources.Load<Texture> ("WavePlayer3"),
			Resources.Load<Texture> ("WavePlayer4")
		};

		enemyWaveTex = new Texture[4] {
			Resources.Load<Texture> ("WaveEnemy1"),
			Resources.Load<Texture> ("WaveEnemy2"),
			Resources.Load<Texture> ("WaveEnemy3"),
			Resources.Load<Texture> ("WaveEnemy4")
		};

		chargeTex = new Texture[5] {
			Resources.Load<Texture> ("Speaker0"),
			Resources.Load<Texture> ("Speaker1"),
			Resources.Load<Texture> ("Speaker2"),
			Resources.Load<Texture> ("Speaker3"),
			Resources.Load<Texture> ("Speaker4"),
		};

		waveShotAudio = new AudioClip[5] {
			Resources.Load<AudioClip> ("Level 1 Blast"),
			Resources.Load<AudioClip> ("Level 2 Blast"),
			Resources.Load<AudioClip> ("Level 3 Blast"),
			Resources.Load<AudioClip> ("Level 4 Blast"),
			Resources.Load<AudioClip> ("Enemy Wave")
		};

		waveChargeAudio = new AudioClip[3]{
			Resources.Load<AudioClip> ("Charge 2"),
			Resources.Load<AudioClip> ("Charge 3"),
			Resources.Load<AudioClip> ("Charge 4")
		};

		reverdAudio = Resources.Load<AudioClip> ("Reverb");
		waveShrinkAudio = Resources.Load<AudioClip> ("Wave Shrunk");
		waveDestroyAudio = Resources.Load<AudioClip> ("Wave Destroyed");
		playerHitAudio = Resources.Load<AudioClip> ("Player Hit Static");
		gameOverAudio = Resources.Load<AudioClip> ("Game Over");

		playerWaveCBL = -0.46f;

		enemyWaveCBL = new float[4]{ -0.12f, 0, 0.12f, 0.26f };

		waveLevelOffsetDivider = new float[4]{2,3,5,12};

		enemySpawnLocations = new Vector3[4];
		enemySpawnLocations [0] = enemySpawnPoints [0].transform.position;
		enemySpawnLocations [1] = enemySpawnPoints [1].transform.position;
		enemySpawnLocations [2] = enemySpawnPoints [2].transform.position;
		enemySpawnLocations [3] = enemySpawnPoints [3].transform.position;

		destroyedWave = Resources.Load<GameObject> ("_DestroyedWave");

		waveShotRotation = wavePrefab.transform.rotation.eulerAngles;
		spawnDirection = Direction.Down;
		SetEnemySpawnTime ();
		spawnTimer = 0;
		velocityMulitplier = 1;
		scoreTimer = 0;
		challengeTimer = 0;
		gameState = GameState.Playing;
	}
	
	// Update is called once per frame
	void Update () {
		UpdateGameState ();
		switch (gameState) {
		case GameState.Playing:
			scoreTimer += (Time.deltaTime);
			challengeTimer += (Time.deltaTime * 10);
			UpdateChallengeLevel();
			spawnTimer += (Time.deltaTime * 10);
			if (spawnTimer >= enemySpawnTime) {
				SpawnEnemyWave ();
				spawnTimer = 0;
			}
			break;
		case GameState.GameOver:
			break;
		}
		UpdateUIText();
	}

	private void UpdateUIText(){
		string ui = "Health : " + player.GetComponent<Player> ().health + "\nTime : " + GetTime();
		uiText.GetComponent<Text> ().text = ui;
	}

	private void UpdateGameState(){
		if (gameState == GameState.Playing) {
			if (player.GetComponent<Player> ().Health < 0) {
				gameState = GameState.GameOver;
			}
		}
	}


	private void UpdateChallengeLevel(){
		if (challengeTimer >= challengeIncrease) {
			challengeTimer = 0;
			challengeLevel += 1;
			enemySpawnRate *= (challengeLevel - 1) / 4 + 1;
			if (spawnVelocity < 10) {
				spawnVelocity *= 1.2f;
			}
			SetEnemySpawnTime ();
		}
	}

	private string GetTime(){
		string timerS;
		int timeInt = (int)Mathf.Floor (scoreTimer);
		timerS = (timeInt / 60) + ":" + (timeInt % 60).ToString("00");
		return timerS;
	}

	private void SetEnemySpawnTime(){
		enemySpawnTime = 1000 / (enemySpawnRate);
		if (enemySpawnTime < 1) {
			enemySpawnTime = 1;
		}
	
	}

	//Spawn wave
	private void SpawnEnemyWave(){
		int ep = SetRandomSpawn ();
		Wave.CreateNewWave ((GameObject)Instantiate (wavePrefab, enemySpawnLocations[ep], Quaternion.Euler (waveShotRotation)), WaveType.Enemy,
			RandomRangeInt (1.0f, 4.0f), spawnDirection, spawnVelocity * velocityMulitplier, 0.0f);
	}

	//generate random int number between min and max
	private int RandomRangeInt(float min, float max){
		float ran = Random.Range (min - 1.0f, max) + 1;
		if (ran != max + 1) {
			return (int)Mathf.Floor(ran);
		} else {
			return RandomRangeInt (min, max);
		}
	}

	//set up next spawn point and return int for array call
	private int SetRandomSpawn(){
		int ran = RandomRangeInt(0.0f, 3.0f);
		switch (ran) {
		case 0: //coming from top
			waveShotRotation.z = (180);
			spawnDirection = Direction.Down;
			velocityMulitplier = 1;
			break;
		case 1: //coming from bottom
			waveShotRotation.z = (0);
			spawnDirection = Direction.Up;	
			velocityMulitplier = 1;
			break;
		case 2: //coming from left
			waveShotRotation.z = (-90);
			spawnDirection = Direction.Right;	
			velocityMulitplier = 2;
			break;
		case 3: //coming from right
			waveShotRotation.z = (90);
			spawnDirection = Direction.Left;
			velocityMulitplier = 2;
			break;
		}
		return ran;
	}

	/*
	public void SpawnWave(Vector3 spawnPoint, WaveType type, int level, Direction waveDirection){
		//GameObject newWave = (GameObject)Instantiate(waveObject, spawnPoint, Quaternion.Euler(waveRotation));
		//Wave.CreateNewWave (newWave, type, level, waveDirection);
	}
	*/
}
