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

public class NodeController : MonoBehaviour {
	private static readonly float SegCount = 360;
	private static readonly float SegAngle = 360f / SegCount;
	private static readonly float WalkingSpeed = 2f;

	private static readonly HSBColor positiveColor = HSBColor.FromColor (new Color (0f, 0f, 1f, 1f));
	private static readonly HSBColor neutralColor = HSBColor.FromColor (new Color (1f, 1f, 1f, 1f));
	private static readonly HSBColor negativeColor = HSBColor.FromColor (new Color (1f, 0f, 0f, 1f));

	private static int NextWaveId = 0;

	public SpriteRenderer sprite;
	public float broodingSpeed = 2f;
    public float broodEmitTrigger = -80f;
	public float waveCenterAttraction = 0f;
	public EmitConfig emission;
    public float timeToFade = 1f;

	public Color glowColor;

	private Queue<int> wavesAffectedBy = new Queue<int> ();

	// Use this for initialization
	void Start () {
		if (this.emission.emit == true) {
			this.StartCoroutine(this.Emit());
		}
	}

	void OnTriggerEnter2D(Collider2D other) {
		var wave = other.GetComponent<WaveController> ();
		if (this.wavesAffectedBy.Contains (wave.waveId) == false) {
			this.AddWaveAffectedBy (wave.waveId);
			wave.fadeToBlack = true;

			this.StartCoroutine(this.Emit ());
		}
	}

	private IEnumerator Emit() {
		var waveId = NextWaveId;
		NextWaveId++;

		var renderer = this.GetComponentInChildren<SpriteRenderer> ();
		var initialColor = renderer.color;

		var dt = 0f;

		while (dt <= this.emission.interval) {
			dt += Time.deltaTime;
			renderer.color = Color.Lerp (initialColor, this.glowColor, dt / this.emission.interval);

			yield return null;
		}

		renderer.color = initialColor;

		for (int i = 0; i < this.emission.emitCount; i++) {
            this.ShootWave (0f, 360f, 0f, waveId);
		}
	}

	private IEnumerator Move(Vector2 direction) {
		while (direction.magnitude > 0.001f) {
			var move = Vector2.MoveTowards (Vector2.zero, direction, Time.deltaTime * WalkingSpeed);
			this.transform.position += (Vector3)move;

			direction -= move;

			yield return null;
		}
	}

	public void ShootWave(float angle, float frontAngle, float power, int waveId) {
		var container = new GameObject ();
		container.name = "Wave";
		container.transform.position = new Vector3(this.transform.position.x, this.transform.position.y, -1f);

		this.AddWaveAffectedBy (waveId);

		this.StartCoroutine (this.HandleWaveSegments (container, waveId, angle, frontAngle));
	}

	public IEnumerable HandleWaveSegments(GameObject container, int waveId, float angle, float frontAngle) {
		var segments = Mathf.RoundToInt(frontAngle / SegAngle);
		var waves = new List<GameObject>();

		for (int i = 0; i < segments; i++) {
			var segmentAngle = angle + (i - (segments - 1) / 2f) * SegAngle;
            //var wave = GameManager.Instance.poolManager.GetFromPool("Wave");
            var wave = GameObject.Instantiate(GameManager.Instance.waveSegmentPrefab);

            wave.transform.parent = container.transform;
			wave.transform.localPosition = Vector3.zero;
			wave.transform.localScale = new Vector3 (0f, 1f, 1f);

			var waveController = wave.GetComponent<WaveController> ();
			waveController.waveId = waveId;
			waveController.center = (Vector2)this.transform.position;
			waveController.color = this.emission.waveColor;
            waveController.fadeToBlack = false;
            waveController.destroy = false;

            var sprite = wave.GetComponentInChildren<SpriteRenderer> ();
			sprite.color = this.sprite.color;

			wave.transform.rotation = Quaternion.Euler (0f, 0f, segmentAngle + 90f);
			waves.Add (wave);
		}

		var scaleSpeed = Mathf.Sin (Mathf.Deg2Rad * 180f / SegCount) * 2f * this.emission.speed;
		var waveTime = this.emission.range / this.emission.speed;
		var fadeSpeed = 1f / waveTime;

		var dt = 0f;
		var alive = true;
		var fade = false;
		while (alive && dt < waveTime) {
			alive = false;
			dt += Time.deltaTime;

			foreach (var wave in waves) {
				if (wave == null) {
					continue;
				}

				var waveController = wave.GetComponent<WaveController> ();
				fade = fade || waveController.fadeToBlack;
				if (waveController.destroy) {
					wave.transform.parent = null;
                    GameObject.Destroy (wave);
                    //GameManager.Instance.poolManager.ReturnToPool(wave);

					continue;
				}

				alive = true;

				var dir = -wave.transform.up;
				wave.transform.position += dir * this.emission.speed * Time.deltaTime;
				wave.transform.localScale += new Vector3 (scaleSpeed * Time.deltaTime, 0f, 0f);

				if (fade) {
					var sprite = wave.GetComponentInChildren<SpriteRenderer> ();
					var color = sprite.color;
					color.a -= Time.deltaTime / this.timeToFade;
					sprite.color = color;

					if (color.a <= 0) {
						waveController.destroy = true;
					}
				}
			}

			yield return null;
		}

		foreach (var wave in waves) {
			if (wave) {
				wave.transform.parent = null;
				GameObject.Destroy (wave);
                //GameManager.Instance.poolManager.ReturnToPool(wave);
            }
		}

		if (container.transform.childCount == 0) {
			GameObject.Destroy (container);

            if (waveId == NextWaveId - 1)
            {
                this.StartCoroutine(this.GameOver());
            }
		}
	}

    private IEnumerator GameOver()
    {
        var time = 0.5f;
        var dt = 0f;

        var overlay = GameManager.Instance.gameOverOverlay;
        var text = GameManager.Instance.gameOverText;

        while (dt < time)
        {
            dt += Time.deltaTime;
            overlay.color = Color.Lerp(new Color(0f, 0f, 0f, 0f), new Color(0f, 0f, 0f, 0.7f), dt / time);
            text.color = Color.Lerp(new Color32(0x94,0x94,0x94,0x00), new Color32(0x94, 0x94, 0x94, 0xFF), dt / time);
            yield return null;
        }

        yield return new WaitForSeconds(3f);

        Scene loadedLevel = SceneManager.GetActiveScene();
        SceneManager.LoadScene(loadedLevel.buildIndex);
    }

    private void AddWaveAffectedBy(int waveId) {
		// Save affecting wave
		this.wavesAffectedBy.Enqueue (waveId);

		// Some clean-up
		if (this.wavesAffectedBy.Count > 10) {
			this.wavesAffectedBy.Dequeue ();
		}
	}



}

[Serializable]
public class EmitConfig {
	public bool emit = false;
	public float interval = 2f;
	public float range = 8f;
	public float speed = 8f;
	public float multiplier = 0.1f;
	public int emitCount = 3;
	public WaveColor waveColor;
}