﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using PhotonHashTable = ExitGames.Client.Photon.Hashtable;

public class CircleScript : MonoBehaviour {

	public List<int> stormTimes;
	public GameObject smog;

	Transform circle;
	int damageRate = 1;
	int circleNum = 0;
	float startSize = 900f, circleSize;
	Vector2 lastPoints;
    PhotonView view;
    CircleTimeDisplay circleTimeDisplay;

    // Use this for initialization
    void Start () {
		circle = transform.parent;
		circleSize = startSize;
        view = GetComponent<PhotonView>();
        GameObject obj = GameObject.FindGameObjectWithTag("Game Manager");
        if (obj) {
            circleTimeDisplay = obj.GetComponent<CircleTimeDisplay>();
        }
        else {
            Debug.Log("Can't find object with tag Game Manager");
        }
        StartCoroutine(WaitAndStartCircle());
    }

    IEnumerator WaitAndStartCircle() {
        if (!PhotonNetwork.IsConnected) {
            while (GridHandler.initializing) {
                yield return null;
            }
        }
        else {
            bool completed = false;
            while (!completed) {
                Dictionary<int, Photon.Realtime.Player> players = PhotonNetwork.CurrentRoom.Players;
                completed = true;
                foreach (KeyValuePair<int, Photon.Realtime.Player> player in players) {
                    PhotonHashTable playerTable = player.Value.CustomProperties;
                    object prop;
                    if (playerTable.TryGetValue("loading", out prop)) {
                        if ((bool)prop) {
                            completed = false;
                            yield return null;
                            break;
                        }
                    }
                }
            }
            
        }
        
        StartCoroutine(ShrinkCircle());
    }

    // Update is called once per frame
    void Update () {

	}

	void OnTriggerEnter (Collider col) {
		if (col.tag == "MainCamera") {
			smog.SetActive (false);
		}

		if (col.tag == "Player") {
            GameObject player = col.gameObject;
            if (!CheckIfPlayerIsMe(player)) {
                return;
            }
			player.GetComponent<PlayerBase> ().inStorm = false;
		}
			
	}

	void OnTriggerExit (Collider col) {
		if (col.tag == "MainCamera") {
			smog.SetActive (true);
		}

		if (col.tag == "Player") {
            GameObject player = col.gameObject;
            if (!CheckIfPlayerIsMe(player)) {
                return;
            }
            StartCoroutine (PlayerInStorm (col.gameObject));
		}
	}

    bool CheckIfPlayerIsMe(GameObject player) {
        PhotonView view = player.GetComponent<PhotonView>();
        if (view && !view.IsMine) {
            return false;
        }
        return true;
    }

	void AdjustSize () {
		circleNum++;
		damageRate++;
        Debug.Log(circleSize);
		circleSize = circleSize / 2f;
	}

    IEnumerator ShrinkCircleToPoints(Vector2 circlePoints) {
        float t = 0f;
        Vector3 startScale = circle.localScale;
        Vector3 startPos = circle.position;
        lastPoints = circlePoints;
        Vector3 newPos = new Vector3(circlePoints.x, -150f, circlePoints.y);
        if (circleTimeDisplay) {
            circleTimeDisplay.SetStormWaiting(false);
            if (PhotonNetwork.IsConnected && PhotonNetwork.IsMasterClient) {
                float timeToCircleCloses = 30f;
                if (circleNum < 4) {
                    timeToCircleCloses = stormTimes[circleNum + 1];
                }
                float nextStormTime = timeToCircleCloses + (PhotonNetwork.IsConnected ? (float)PhotonNetwork.Time : Time.unscaledTime);
                circleTimeDisplay.SetNextStormTime(nextStormTime);
                PhotonDebugger.IncrementNumberOfMessages("circle");
                view.RPC("SetStormTime", RpcTarget.OthersBuffered, nextStormTime);
            }
            else {
                float timeToCircleCloses = 30f;
                if (circleNum < 4) {
					timeToCircleCloses = stormTimes[circleNum + 1];
                }
                float nextStormTime = timeToCircleCloses + (PhotonNetwork.IsConnected ? (float)PhotonNetwork.Time : Time.unscaledTime);
                circleTimeDisplay.SetNextStormTime(nextStormTime);
            }
        }
        while (t < 1) {
            if (circleNum < 4) {
				t += Time.deltaTime / stormTimes[circleNum + 1];
            }
            else {
                t += Time.deltaTime / 60f;
            }
            circle.localScale = Vector3.Lerp(startScale, new Vector3(circleSize, 100, circleSize), t);
            circle.position = Vector3.Lerp(startPos, newPos, t);
            yield return null;
        }
        if (circleTimeDisplay)
            circleTimeDisplay.SetStormWaiting(true);
        AdjustSize();
    }

    IEnumerator ShrinkCircle () {
		while(circleNum <= 3) {
            if (PhotonNetwork.IsConnected && PhotonNetwork.IsMasterClient && view) {
                // send how long until the next circle (also works as the time it takes for the next one to close might want to update this)
                PhotonDebugger.IncrementNumberOfMessages("circle");
                view.RPC("SetStormTime", RpcTarget.OthersBuffered, (float)PhotonNetwork.Time + stormTimes[circleNum]);
                if (circleTimeDisplay)
                    circleTimeDisplay.SetNextStormTime((float)PhotonNetwork.Time + stormTimes[circleNum]);
                yield return new WaitForSecondsRealtime(stormTimes[circleNum]);

                // send the next circle points 
                Vector2 circlePoints = (circle.localScale.x > 1200) ? Random.insideUnitCircle * 281.8f : (Random.insideUnitCircle * (circle.localScale.x / 2f - (circleSize / 2f)) + lastPoints);
                PhotonDebugger.IncrementNumberOfMessages("circle");
                view.RPC("StartCircleShrinkToPoints", RpcTarget.OthersBuffered, circlePoints);

                yield return StartCoroutine(ShrinkCircleToPoints(circlePoints));
            }
            else if (!PhotonNetwork.IsConnected) {
                // there's an enormous delay when starting in editor where it sets the next time
                // but it doesn't actually start running for a few seconds so the first circle comes faster for no reason
                // so just do a quick yield return here
                yield return null;
                if (circleTimeDisplay)
                    circleTimeDisplay.SetNextStormTime((float)Time.unscaledTime + stormTimes[circleNum]);
                yield return new WaitForSecondsRealtime(stormTimes[circleNum]);

                Vector2 circlePoints = (circle.localScale.x > 1200) ? Random.insideUnitCircle * 281.8f : (Random.insideUnitCircle * (circle.localScale.x / 2f - (circleSize / 2f)) + lastPoints);
                yield return StartCoroutine(ShrinkCircleToPoints(circlePoints));
            }
            else {
                // if not master just keep running the coroutine just in case you become the master
                // every three seconds check if you are the master
                yield return new WaitForSecondsRealtime(3.0f); 
            }
        }

        StartCoroutine(ShrinkCircleUntilNothingIsLeft());
	}

    IEnumerator ShrinkCircleUntilNothingIsLeft() {
        while (circle.localScale.x > 0.01f) {
            if (PhotonNetwork.IsConnected && PhotonNetwork.IsMasterClient && view) {
                // send how long until the next circle (also works as the time it takes for the next one to close might want to update this)
                PhotonDebugger.IncrementNumberOfMessages("circle");
                view.RPC("SetStormTime", RpcTarget.OthersBuffered, (float)PhotonNetwork.Time + stormTimes[3]);
                if (circleTimeDisplay)
                    circleTimeDisplay.SetNextStormTime((float)PhotonNetwork.Time + stormTimes[3]);
                yield return new WaitForSecondsRealtime(stormTimes[3]);

                // send the next circle points 
                Vector2 circlePoints = (circle.localScale.x > 1200) ? Random.insideUnitCircle * 281.8f : (Random.insideUnitCircle * (circle.localScale.x / 2f - (circleSize / 2f)) + lastPoints);
                PhotonDebugger.IncrementNumberOfMessages("circle");
                view.RPC("StartCircleShrinkToPoints", RpcTarget.OthersBuffered, circlePoints);

                yield return StartCoroutine(ShrinkCircleToPoints(circlePoints));
            }
            else if (!PhotonNetwork.IsConnected) {
                // there's an enormous delay when starting in editor where it sets the next time
                // but it doesn't actually start running for a few seconds so the first circle comes faster for no reason
                // so just do a quick yield return here
                yield return null;
                if (circleTimeDisplay)
                    circleTimeDisplay.SetNextStormTime((float)Time.unscaledTime + stormTimes[3]);
                yield return new WaitForSecondsRealtime(stormTimes[3]);

                Vector2 circlePoints = (circle.localScale.x > 1200) ? Random.insideUnitCircle * 281.8f : (Random.insideUnitCircle * (circle.localScale.x / 2f - (circleSize / 2f)) + lastPoints);
                yield return StartCoroutine(ShrinkCircleToPoints(circlePoints));
            }
            else {
                // if not master just keep running the coroutine just in case you become the master
                // every three seconds check if you are the master
                yield return new WaitForSecondsRealtime(3.0f);
            }
        }
    }


    IEnumerator PlayerInStorm (GameObject player) {
		PlayerBase pBase = player.GetComponent<PlayerBase> ();
		pBase.inStorm = true;
		yield return new WaitForSeconds (0.5f);
		while (pBase.inStorm) {
            pBase.DoDamage(damageRate);
			yield return new WaitForSeconds (1f);
		}
		yield return null;
	}

    [PunRPC]
    public void SetStormTime(float currentStormTime) {
        // make the timer appear with this 
        if(circleTimeDisplay)
            circleTimeDisplay.SetNextStormTime(currentStormTime);
    }

    [PunRPC]
    public void StartCircleShrinkToPoints(Vector2 circlePoints) {
        StartCoroutine(ShrinkCircleToPoints(circlePoints));
    }
}
