using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using System.Linq;
using System.IO;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using TMPro;
using UnityEditor;


[System.Serializable]
public class TrackManagerScript : MonoBehaviourPunCallbacks
{    
    [Header("Racetrack Options")]
    [SerializeField] [Range(1, 5)] int m_laps = 3;
    public int LapsInRace { get { return m_laps; } }
    [SerializeField] Color m_trackPrimaryColor = new Color(0.3216002f, 0.5819195f, 0.9339623f);
    [SerializeField] Color m_trackSecondaryColor = new Color(0.1603774f, 0.136926f, 0.136926f);
    [BoolToButton("", "")] [SerializeField] bool m_uiSpace1;
    [BoolToButton("m_setAllTrackColors", "Set Track Colors")]
    [SerializeField] bool m_setAllTrackColors = false;
    [BoolToButton("", "")] [SerializeField] bool m_uiSpace2;

    [Header("Defaults")]
    public Transform trackStart;
    public Transform racerSpots;
	[ReadOnly]
	public Texture sampleFile;

	[Header("Scene References")]
	[SerializeField] List<SceneField> m_excludedScenes = new List<SceneField>();

	[SerializeField] static List<string> m_availableTrackNames;

	[ReadOnly]
	public bool loadSceneCalled = false, VotingGUIActive = false;
	[ReadOnly]
	public Vector2 scrollSpot;
	[ReadOnly]
	public GUISkin sampleSkin;
	[ReadOnly]
	public GUIContent[] playableTracks;
	[ReadOnly]
	public Vote leadingVote;
	[ReadOnly]
	public Vote[] trackVotes;
	[ReadOnly]
	public int selectGridInt = 0, gridSpots = 4;
	[ReadOnly]
	public string selectedLevel = "";

	[ReadOnly]
	public CanvasManagerScript canvasManager;

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

    private void OnValidate()
    {
        if (m_setAllTrackColors)
        {
            if (m_debugChannel)
                m_debugChannel.Raise(this, "Setting track colors");

            foreach (ModularTrack _track in FindObjectsOfType<ModularTrack>())
            {
                ColorChanger _cc = GetComponent<ColorChanger>();

                if (_cc && _cc.objectColors.Length >= 2)
                {
                    _cc.objectColors[0] = m_trackPrimaryColor;
                    _cc.objectColors[1] = m_trackSecondaryColor;
                    _cc.ConvertMaterials();
                }

                foreach (ColorChanger _colorChanger in _track.GetComponentsInChildren<ColorChanger>())
                    if (_colorChanger && _colorChanger.objectColors.Length >= 2)
                    {
                        _colorChanger.objectColors[0] = m_trackPrimaryColor;
                        _colorChanger.objectColors[1] = m_trackSecondaryColor;
                        _colorChanger.ConvertMaterials();
                    }
            }

            AdaptiveTrack _at = FindObjectOfType<AdaptiveTrack>();

            if (_at)
            {
                ColorChanger _cc = _at.GetComponent<ColorChanger>();

                if (_cc && _cc.objectColors.Length >= 2)
                {
                    _cc.objectColors[0] = m_trackPrimaryColor;
                    _cc.objectColors[1] = m_trackSecondaryColor;
                    _cc.ConvertMaterials();
                }
            }

            m_setAllTrackColors = false;
        }
    }

    void Start ()
    {
        if (SceneManager.GetActiveScene().name.Contains("Custom Racer Creator"))
            return;

        SetDefaults();

        selectGridInt = -1;

        PopulateAvailableTracks();

        Vector3 adjustedPos = new Vector3(trackStart.position.x, trackStart.position.y + 1.13f, trackStart.position.z - 2f);

        if (racerSpots && SceneManager.GetActiveScene().name != "RKR - Esports Lobby")
        {
            if (PhotonNetwork.IsConnected)
            {
                bool joinAsSpectator = false;

                object prop;

                if (PhotonNetwork.LocalPlayer.CustomProperties.TryGetValue("IsSpectator", out prop))
                {
                    joinAsSpectator = (bool)prop;
                    canvasManager.RaceOrSpectateCanvas(joinAsSpectator);

                    if (joinAsSpectator)
                    {
                        Debug.Log(PhotonNetwork.LocalPlayer.ActorNumber - 1 + " - Player is Specator");

                        SpectatorController spectatorController = FindObjectOfType<SpectatorController>();
                        spectatorController.SpectateAnyPlayer();
                    }
                    else
                    {

                        //Debug.Log(PhotonNetwork.LocalPlayer.ActorNumber - 1);
                        GameObject newPlayer = PhotonNetwork.Instantiate("New Racer", racerSpots.GetChild(PhotonNetwork.LocalPlayer.ActorNumber - 1).position, trackStart.rotation);
                    }
                }

            }
            else
            {
                Instantiate(Resources.Load("New Racer"), racerSpots.GetChild(0).position, trackStart.rotation);
            }
        }

        /*
		if (SceneManager.GetActiveScene ().name != "PhotonTesting 1" && SceneManager.GetActiveScene ().name != "RKR-Lobby" && SceneManager.GetActiveScene().name != "Esports-Lobby") {
			guiActive = false;
		} else { 
			guiActive = true;
		}
		*/
    }

    private void SetDefaults()
    {
        if (!trackStart)
            trackStart = GameObject.FindGameObjectWithTag("StartFinish").transform;

        if (!racerSpots)
            racerSpots = GameObject.Find("Racer Spots").transform;

        if (!sampleFile)
            sampleFile = Resources.Load<Texture>("Button Images/RKR Icon");

        if (!sampleSkin)
            sampleSkin = Resources.Load<GUISkin>("Button Images/TrackSelectSkin");

        if (!canvasManager)
            canvasManager = GetComponentInChildren<CanvasManagerScript>();
    }

    // EXECUTABLE METHODS //
    #region
    /// <summary>
    /// Populates the available tracks field
    /// </summary>
    void PopulateAvailableTracks ()
    {
		if (m_debugChannel)
        {
			m_debugChannel.Raise(this, "Getting scenes...");

            m_debugChannel.Raise(this, "There are currently " + SceneManager.sceneCountInBuildSettings + " scenes in the build.");
        }

        if (SceneManager.sceneCountInBuildSettings <= 2)
        {
            if (m_debugChannel)
                m_debugChannel.Raise(this, "No custom scenes available!");

            return;
        }

        // Create a new list to hold track names
		m_availableTrackNames = new List<string> ();

        // For each scene in our build settings starting at 2 (0 and 1 are lobby/customizer scenes)
		for (int i = 2; i < SceneManager.sceneCountInBuildSettings; i++)
        {
            if (m_debugChannel)
            {
                m_debugChannel.Raise(this, "Checking scene index " + i);
                m_debugChannel.Raise(this, "Scene " + i + " is " + SceneUtility.GetScenePathByBuildIndex(i));
            }

            // Assume we are not excluding the track
            bool excluded = false;
			
            // Check each excluded scene name
            foreach (SceneField _scene in m_excludedScenes)
                // If there is a match in the given scene...
                if (SceneUtility.GetScenePathByBuildIndex(i).Contains(_scene.SceneName))
                {
                    // Exclude the scene
                    excluded = true;

					if (m_debugChannel)
						m_debugChannel.Raise(this, "Scene excluded because the name contains " + _scene + "!");

                    break;
                }

            // If this scene is excluded, continue to the next scene
            if (excluded) { continue; }

            // Otherwise, add this scene to the track list and remove its path info and file name
			m_availableTrackNames.Add (SceneUtility.GetScenePathByBuildIndex (i).Replace ("Assets/Racetrack Scenes/", "").Replace ("Demo Tracks/", "").Replace (".unity", ""));
		}

        // If we didn't get any tracks, return
        if (m_availableTrackNames.Count < 1)
            return;

        // Create a new array of GUIContent that matches the number of tracks
		playableTracks = new GUIContent[m_availableTrackNames.Count];

        // Create a new vote array of the same size
		trackVotes = new Vote[m_availableTrackNames.Count];

        // For each track in the list of names...
		for (int t = 0; t < m_availableTrackNames.Count; t++)
        {
            // Populate the vote array with a new vote associated with that name
			trackVotes [t] = new Vote (m_availableTrackNames [t], 0);

            // Do the same for the GUIcontent
			playableTracks [t] = new GUIContent (m_availableTrackNames [t].Replace("(Demo)", ""), sampleFile);
		}

        // By default,, the leading vote and selected level will be the first available level
		leadingVote = trackVotes [0];
		selectedLevel = trackVotes [0].name;

		if (m_debugChannel)
			m_debugChannel.Raise(this, "Found " + m_availableTrackNames.Count + " levels.");
	}
    #endregion

    public static bool FindTracks () 
    {
		Debug.Log ("[TrackManagerScript] Scene Count Build Settings: " + SceneManager.sceneCountInBuildSettings);

        bool _found = false;

		for (int i = 2; i < SceneManager.sceneCountInBuildSettings; i++)
        {
            _found = true;

			string[] _substrings = SceneUtility.GetScenePathByBuildIndex(i).Split('/');

			Debug.LogError ("[TrackManagerScript] Found " + _substrings[_substrings.Length - 1].Replace (".unity", "").Replace("(Demo)", ""));
		}

		return _found;

		// Deprecated track-finding method
        #region
        /*
		string[] tempNames = Directory.GetFiles (Application.dataPath + "/Racetrack Scenes");
		trackNames = new List<string> ();

		if (tempNames.Length < 1) {
			Debug.Log ("None");
			return false;
		}
		foreach (string track in tempNames) {
			if (!track.Contains (".meta")) {
				#if UNITY_EDITOR_WIN
				string trackName = track.Substring(track.LastIndexOf('\\') + 1);
				#else
				string trackName = track.Substring(track.LastIndexOf('/') + 1);
				#endif
				trackNames.Add (trackName.Replace (".unity", ""));
			}
		}

		return true;
		*/
        #endregion
    }

    void OnGUI () 
	{
		if (!VotingGUIActive)
			return;

		if (!SceneManager.GetActiveScene().name.Contains("RKR - Esports Lobby"))
			return;

        Rect innerBorder = new Rect (Screen.width / 16f, Screen.height / 16f, Screen.width * (7f / 8f), Screen.height * (7f / 8f));
		Rect outerBorder = new Rect (Screen.width / 32f, Screen.height / 32f, Screen.width * (15f / 16f), Screen.height * (15f / 16f));
		
		GUILayout.BeginArea (outerBorder);

		scrollSpot = GUILayout.BeginScrollView (scrollSpot);

		GUILayout.BeginHorizontal ();
		GUILayout.FlexibleSpace ();
		GUILayout.BeginVertical ();
		GUILayout.FlexibleSpace ();

		if (selectGridInt == -1) 
		{
			selectGridInt = GUILayout.SelectionGrid (selectGridInt, playableTracks, gridSpots, sampleSkin.button, GUILayout.MaxWidth(innerBorder.width));
		} 
		else 
		{
			GUILayout.SelectionGrid (selectGridInt, playableTracks, gridSpots, sampleSkin.customStyles[3], GUILayout.MaxWidth(innerBorder.width));

			if (PhotonNetwork.IsConnected) 
			{
				photonView.RPC ("CastVote", RpcTarget.AllBuffered, selectGridInt);
			} 
			else 
			{
                if (m_debugChannel)
                    m_debugChannel.Raise(this, m_availableTrackNames[selectGridInt] + " selected! Loading scene...");

				SceneManager.LoadScene (m_availableTrackNames [selectGridInt]);
			}

			VotingGUIActive = false;
		}

		GUILayout.FlexibleSpace ();
		GUILayout.EndVertical ();
		GUILayout.FlexibleSpace ();
		GUILayout.EndHorizontal ();


		GUILayout.EndScrollView ();
		GUILayout.EndArea ();
	}

    // COROUTINES //
    #region
    IEnumerator LoadRacetrack (int trackNum) 
	{
		if (loadSceneCalled)
			yield break;

		loadSceneCalled = true;

		yield return new WaitForSecondsRealtime (2f);

		SceneManager.LoadScene (m_availableTrackNames [trackNum]);
	}
    #endregion

    // PHOTON/RPC //
    #region
    [PunRPC]	
	public void CastVote (int trackSceneNum) {
		trackVotes [trackSceneNum].AddVote (1);
		
        if (m_debugChannel)
            m_debugChannel.Raise(this, trackVotes [trackSceneNum].tally.ToString() + " votes for " + SceneManager.GetSceneByBuildIndex(trackSceneNum).name);

		for (int i = 0; i < trackVotes.Length; i++) {
			if (leadingVote.tally < trackVotes [i].tally) {
				leadingVote = trackVotes [i];
			}
		}

		selectedLevel = leadingVote.name;

		if (m_debugChannel)
			m_debugChannel.Raise(this, "Vote received for " + selectedLevel);
	}
    #endregion
}

[System.Serializable]
public class TrackQuadrant {
	public ModularTrack start, turn, end;
}

[System.Serializable]
public class Vote {
	public string name;
	public int tally;

	public Vote (string voteName, int voteTally) {
		name = voteName;
		tally = voteTally;
	}

	public void AddVote (int value) {
		tally += value;
	}
}
