using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using Photon.Pun;

public class RacerLobbyUI : MonoBehaviour {

    [Header("References")]
	public GameLauncher m_gameLauncher;
	public TrackManagerScript m_trackManager;
	[SerializeField] LobbyCanvasHandler m_lobbyCanvasHandler;

    [Header("Lobby Info")]
    [SerializeField] [ReadOnly] bool m_countingDown;
    [SerializeField] [ReadOnly] bool m_thirtySecondsPassed = false;
    [SerializeField] [ReadOnly] bool m_fullGame = false;
	[SerializeField] [ReadOnly] float m_timeAtLoad;
	[SerializeField] [ReadOnly] int m_lastPlayerCount = 0;

    [Header("Lobby Text")]
    [SerializeField] TMP_Text m_waitForPlayersTimer;
    [SerializeField] TMP_Text m_waitForPlayersText;
    [SerializeField] TMP_Text m_startMatchText;
    [SerializeField] TMP_Text m_countdownTimer;
    [SerializeField] TMP_Text m_racerCount;

    [Header("Settings")]
    [SerializeField] [Min(30)] float m_startWaitTime = 59f;
    [SerializeField] [Min(15)] float m_extraPlayers = 30f;
	[SerializeField] float m_timeToWaitBeforeLoad = 1f;

	[Header("Debug")]
	[SerializeField] DebugChannelSO m_debugChannel;

    // PRIVATE VALUES //
    #region
    bool m_wasHost;
    bool m_cancellingCountdown;
    float m_finalCountdownLength = 5f;
    #endregion

    void Start()
    {
		m_timeAtLoad = Time.unscaledTime;
		m_wasHost = PhotonNetwork.IsMasterClient;
        m_gameLauncher = FindObjectOfType<GameLauncher>();
        m_trackManager = FindObjectOfType<TrackManagerScript>();
		StartCoroutine (DotDotDot ());
	}

	void Update()
    {
        // If we are the host, are counting down, and we were not previously the host...
		if(PhotonNetwork.IsMasterClient && m_countingDown && !m_wasHost)
        {
			if (m_debugChannel)
				m_debugChannel.Raise(this, "Became host");

            // Here we call Host to refresh the lobby timer
			Host (false);
			m_wasHost = true;
		}

        // If we are in the room and we are not the master client, we are counting down
		if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient)
        {
			m_countingDown = true;
		}

        // If we are the master client, the launcher has 1 or less players, and the timer is active...
		if (PhotonNetwork.IsMasterClient && m_gameLauncher.totalPlayers <= 1 && m_waitForPlayersTimer.gameObject.activeInHierarchy)
        {
            // Stop counting down
			m_countingDown = false;

            // Run Cancel
			CancelAndReset();

            // Hide the timer
			m_waitForPlayersTimer.gameObject.SetActive(false);
		}
        // Otherwise, if we are the master client and are not counting down...
        else if (PhotonNetwork.IsMasterClient && !m_countingDown)
        {
            // if the total players is greater than one...
			if(m_gameLauncher.totalPlayers > 1)
            {
				if (m_debugChannel)
					m_debugChannel.Raise(this, "Starting lobby countdown");

                // We are counting now
				m_countingDown = true;

                // Set the last player count to the current number of players
				m_lastPlayerCount = m_gameLauncher.totalPlayers;

                // Call host to set the start time
				Host (true);
			}
		}
        // If we are the master client and we are currently counting down...
        else if (PhotonNetwork.IsMasterClient && m_countingDown)
        {
            // If we have gained OR lost players...
			if (m_lastPlayerCount != m_gameLauncher.totalPlayers)
            {
				//Debug.LogError ("Restart Countdown");
				m_lastPlayerCount = m_gameLauncher.totalPlayers;

                // Here we are resetting the timer because the number of players has changed
				Host (false);
			}
		}

        // If we are in a room...
		if (PhotonNetwork.InRoom)
        {
            // If the lobby just became full...
			if (m_gameLauncher.totalPlayers == 8 && !m_fullGame)
            {
                // Cancel the countdown
				m_cancellingCountdown = true;

                // Set the game as full
				m_fullGame = true;

                // Start final countdown
				StartCoroutine (BeginMatchCountdown());
			}

            // Update the persistent value of whether we were the master client this frame
			m_wasHost = PhotonNetwork.IsMasterClient;

            // Set the display of the number of players
			m_racerCount.SetText ("Racers " + m_gameLauncher.totalPlayers + "/" + m_gameLauncher.maxPlayersPerRoom);
		}

        // Debug statement to manually set the start time
		//if (Input.GetKeyDown (KeyCode.P))
		//	Host (false);

		//if (StaticLoadingScreen.activeInHierarchy && Time.unscaledTime > loadingTime) {
		//	StaticLoadingScreen.SetActive(false);
		//}
	}

    // Called from the host of the lobby when a new player joins the lobby
	public void Host(bool initialStart)
    {
        // Send a photone debugger message
		PhotonGameDebugger.IncrementNumberOfMessages("Update match start time [RacerLobbyUI]");

        // The time to send is the Photon Network's Time value cast as a float
        // Why is this registering as being so high? Does this need to be adjusted?
		float sendTime = (float)PhotonNetwork.Time;

		if (m_debugChannel)
			m_debugChannel.Raise(this, "Time at host start is " + sendTime.ToString() + " | " + PhotonNetwork.Time.ToString());

		if (initialStart)
        {
			m_thirtySecondsPassed = false;
			m_cancellingCountdown = false;
			m_gameLauncher.photonView.RPC ("SetMatchStartTime", RpcTarget.AllBuffered, sendTime, sendTime + m_startWaitTime, false);
		}
        else if (m_thirtySecondsPassed)
        {
			m_gameLauncher.photonView.RPC ("SetMatchStartTime", RpcTarget.AllBuffered, sendTime, sendTime + m_extraPlayers, true);
		}
	}

	IEnumerator DotDotDot () {
		while (!PhotonNetwork.InRoom) 
			yield return null;
		
		while (m_gameLauncher.totalPlayers < 8)
        {
			m_waitForPlayersText.SetText ("[ Waiting for more players    ]");

			yield return new WaitForSeconds (0.5f);

			m_waitForPlayersText.SetText ("[ Waiting for more players.   ]");

			yield return new WaitForSeconds (0.5f);

			m_waitForPlayersText.SetText ("[ Waiting for more players..  ]");

			yield return new WaitForSeconds (0.5f);

			m_waitForPlayersText.SetText ("[ Waiting for more players... ]");

			yield return new WaitForSeconds (0.5f);
		}
	}

    public void Cancel()
    {
        m_cancellingCountdown = true;
    }

    public void CancelAndReset()
    {
		m_cancellingCountdown = true;
		m_gameLauncher.ResetMatchStartTime();
	}

	public IEnumerator CountdownToStart()
    {
		
		// Allow for late joiners to catch up
		while ((float)PhotonNetwork.Time > m_gameLauncher.MatchStartTime)
			yield return null;
	

		m_waitForPlayersTimer.gameObject.SetActive(true);

		if (m_debugChannel)
			m_debugChannel.Raise(this, "Cancel Countdown: " + m_cancellingCountdown + ", GMST: " + m_gameLauncher.MatchStartTime.ToString () + ", PNT: " + PhotonNetwork.Time.ToString ());

        while (!m_cancellingCountdown && m_gameLauncher.MatchStartTime > -1 && (float)PhotonNetwork.Time < m_gameLauncher.MatchStartTime)
        {
			if ((m_gameLauncher.MatchStartTime - (float)PhotonNetwork.Time) <= 30f) 
				m_thirtySecondsPassed = true;
			
			m_waitForPlayersTimer.SetText("0:" + (m_gameLauncher.MatchStartTime - (float)PhotonNetwork.Time).ToString("00"));

			yield return null;
		}

		if (m_cancellingCountdown)
        {
			if (m_debugChannel)
				m_debugChannel.Raise(this, "Countdown cancelled");

			m_cancellingCountdown = false;

			yield break;
		}

		m_waitForPlayersTimer.gameObject.SetActive(false);
		m_waitForPlayersText.gameObject.SetActive(false);
		m_startMatchText.gameObject.SetActive(true);

		m_gameLauncher.BeginMatch ((float)PhotonNetwork.Time + m_finalCountdownLength);
	}

	public IEnumerator BeginMatchCountdown()
    {
		m_countdownTimer.gameObject.SetActive(true);

		if (!m_fullGame)
			while (!m_cancellingCountdown && m_gameLauncher.MatchStartTime > -1 && (float)PhotonNetwork.Time < m_gameLauncher.MatchStartTime)
            {
				m_countdownTimer.SetText ((m_gameLauncher.MatchStartTime - (float)PhotonNetwork.Time).ToString ("F0"));

				yield return null;
			}

		m_countdownTimer.gameObject.SetActive(false);

		//StaticLoadingScreen.SetActive(true);

		m_timeAtLoad = Time.unscaledTime + m_timeToWaitBeforeLoad;

		m_lobbyCanvasHandler.SetInLobbyCanvasActive();
		m_gameLauncher.StartMatch();
	}
}