using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using System.Net.NetworkInformation;
using PhotonHashtable = ExitGames.Client.Photon.Hashtable;

public class Launcher : MonoBehaviourPunCallbacks {

    public CloudRegion cloudRegion;

	public GameObject rotCamera;

    string _gameVersion = "1.0";

	public GameObject testPlayer;
	public bool testPlay = false;

    public int maxPlayersPerRoom = 8;
    public int maxSpectatorsPerRoom = 1;
    public bool joinAsSpectator = false;

    int totalPlayers = 0;
    int totalSpectators = 0;

    public TMP_InputField classIDField;
    public TMP_Text joinErrorMessage;

    public LobbyPanelHandler handler;
    //public LobbyUI lobbyUI;

    public float matchStartTime = -1f;

    //public GameGenerator gameGenerator;

    public enum CloudRegion {
        USEast, USWest, Europe, CanadaEast
    }


    public Dictionary<CloudRegion, string> cloudRegionTokens = new Dictionary<CloudRegion, string>() {
        { CloudRegion.USEast, "us" },
        { CloudRegion.USWest, "usw" },
        { CloudRegion.Europe, "eu" },
        { CloudRegion.CanadaEast, "cae" },
    };

    void Awake() {
        totalPlayers = 0;
        totalSpectators = 0;
        joinAsSpectator = false;
        PhotonNetwork.AutomaticallySyncScene = true;

        string token = "us";
        if(cloudRegionTokens.TryGetValue(cloudRegion, out token))
            ((ServerSettings)Resources.Load("PhotonServerSettings", typeof(ServerSettings))).AppSettings.FixedRegion = token;

    }

    public void Connect() {
        if (PhotonNetwork.IsConnected) {
            if(joinAsSpectator) {
                PhotonHashtable playerProperties = new PhotonHashtable() { { "IsSpectator", true }, { "DisplayName", PersistentData.localPlayerData.username } };
                PhotonNetwork.LocalPlayer.SetCustomProperties(playerProperties);
                PhotonHashtable expectedCustomRoomProperties = new PhotonHashtable() { { "spectator_slots_availabile", true } };
                PhotonNetwork.JoinRandomRoom(expectedCustomRoomProperties, (byte)(maxPlayersPerRoom + maxSpectatorsPerRoom));
            }
            else {
                PhotonHashtable playerProperties = new PhotonHashtable() { { "IsSpectator", false } , { "DisplayName", PersistentData.localPlayerData.username } };
                PhotonNetwork.LocalPlayer.SetCustomProperties(playerProperties);
                PhotonHashtable expectedCustomRoomProperties = new PhotonHashtable() { { "player_slots_availabile", true } };
                PhotonNetwork.JoinRandomRoom(expectedCustomRoomProperties, (byte)(maxPlayersPerRoom + maxSpectatorsPerRoom));
            }
        }
        else {
            ((ServerSettings)Resources.Load("PhotonServerSettings", typeof(ServerSettings))).AppSettings.AppVersion = _gameVersion;
            //PhotonNetwork.GameVersion = _gameVersion;
            PhotonNetwork.ConnectUsingSettings();
        }
    }

    public override void OnConnectedToMaster() {
        Debug.Log("OnConnectedToMaster() was called by PUN");
        if (joinAsSpectator) {
            PhotonHashtable playerProperties = new PhotonHashtable() { { "IsSpectator", true } , { "DisplayName", PersistentData.localPlayerData.username } };
            PhotonNetwork.LocalPlayer.SetCustomProperties(playerProperties);
            PhotonHashtable expectedCustomRoomProperties = new PhotonHashtable() { { "spectator_slots_availabile", true } };
            PhotonNetwork.JoinRandomRoom(expectedCustomRoomProperties, (byte)(maxPlayersPerRoom + maxSpectatorsPerRoom));
        }
        else {
            PhotonHashtable playerProperties = new PhotonHashtable() { { "IsSpectator", false } , { "DisplayName", PersistentData.localPlayerData.username } };
            PhotonNetwork.LocalPlayer.SetCustomProperties(playerProperties);
            PhotonHashtable expectedCustomRoomProperties = new PhotonHashtable() { { "player_slots_availabile", true } };
            PhotonNetwork.JoinRandomRoom(expectedCustomRoomProperties, (byte)(maxPlayersPerRoom + maxSpectatorsPerRoom));
        }
    }


    public override void OnDisconnected(DisconnectCause cause) {
        Debug.LogWarningFormat("OnDisconnected() was called by PUN with reason {0}", cause);
    }

    public override void OnJoinRandomFailed(short returnCode, string message) {
        Debug.Log("OnJoinRandomFailed() was called by PUN. No random room available, so we create one.\nCalling: PhotonNetwork.CreateRoom");

        RoomOptions roomOptions = new RoomOptions();
        roomOptions.CustomRoomPropertiesForLobby = new string[] { "player_slots_availabile", "spectator_slots_availabile" };
        roomOptions.CustomRoomProperties = new PhotonHashtable() { { "player_slots_availabile", true }, { "spectator_slots_availabile", true } };
        roomOptions.MaxPlayers = (byte)(maxPlayersPerRoom + maxSpectatorsPerRoom);
        PhotonNetwork.CreateRoom(null, roomOptions);

        // #Critical: we failed to join a random room, maybe none exists or they are all full. No worries, we create a new room.
        //PhotonNetwork.CreateRoom(null, new RoomOptions { MaxPlayers = (byte)(maxPlayersPerRoom + maxSpectatorsPerRoom) });
    }

    public override void OnJoinedRoom() {
        Debug.Log("Region: " + PhotonNetwork.CloudRegion);
        Debug.Log("OnJoinedRoom() called by PUN. Now this client is in a room.");
		if (testPlay && testPlayer != null) {
			GameObject myPlayer = GameObject.Instantiate (testPlayer, new Vector3 (0, 200, 0), Quaternion.identity);
			if(rotCamera)
				rotCamera.GetComponent<Rotate> ().canRot = false;
		} else {
            if (PhotonNetwork.IsMasterClient) {
                Debug.Log("isMaster");
                //int randomSeed = gameGenerator.GenerateSeed();
                //gameGenerator.SendRandomSeed(randomSeed);
            }
            if (!joinAsSpectator) {
                PhotonNetwork.Instantiate("player", new Vector3(0, 200, 0), Quaternion.identity);
                PhotonNetwork.SendRate = 7;
				if(rotCamera)
					rotCamera.GetComponent<Rotate> ().canRot = false;
            }
            else {
                StartCoroutine(SpectatePlayersAfterTheyLoad());
                PhotonNetwork.SendRate = 10;
            }
            CountPeopleInRoom();
        }
    }

    public override void OnPlayerEnteredRoom(Player other) {
        CountPeopleInRoom();
    }

    public override void OnPlayerLeftRoom(Player other) {
        CountPeopleInRoom();
    }

    void CountPeopleInRoom() {
        object value;
        totalPlayers = 0;
        totalSpectators = 0;
        Dictionary<int, Player> players = PhotonNetwork.CurrentRoom.Players;
        foreach (KeyValuePair<int, Player> playerItem in players) {
            if (playerItem.Value.CustomProperties.TryGetValue("IsSpectator", out value)) {
                if ((bool)value) {
                    totalSpectators++;
                }
                else {
                    totalPlayers++;
                }
            }
        }

        if (PhotonNetwork.IsMasterClient) {
            UpdateRoomSlotProperties();
        }
    }

    void UpdateRoomSlotProperties() {
        PhotonHashtable update = new PhotonHashtable { { "player_slots_availabile", totalPlayers < maxPlayersPerRoom }, { "spectator_slots_availabile", totalSpectators < maxSpectatorsPerRoom } };
        PhotonNetwork.CurrentRoom.SetCustomProperties(update);
        //Debug.LogError("players count: " + totalPlayers);
        //Debug.LogError("spectators count: " + totalSpectators);
        //Debug.LogError("total in room: " + (totalSpectators + totalPlayers));
    }

    public void Submit(bool joinAsSpectator) {
        ToggleJoinAsSpectator(joinAsSpectator);
        _gameVersion = "ESPORTS " + classIDField.text.ToUpper();
        if (classIDField.text.Length < 7) {
            joinErrorMessage.gameObject.SetActive(true);
            return;
        }
        joinErrorMessage.gameObject.SetActive(false);
        ((ServerSettings)Resources.Load("PhotonServerSettings", typeof(ServerSettings))).AppSettings.AppVersion = _gameVersion;
        Connect();
        if(joinAsSpectator)
            handler.SetSpectatorPanelActive();
        else
            handler.SetInLobbyPanelActive();

    }

    public void QuickplaySubmit() {
        _gameVersion = "ESPORTS Random Match";
        joinErrorMessage.gameObject.SetActive(false);
        ((ServerSettings)Resources.Load("PhotonServerSettings", typeof(ServerSettings))).AppSettings.AppVersion = _gameVersion;
        Connect();
        handler.SetInLobbyPanelActive();
    }

    public float GetMatchStartTime() {
        return matchStartTime;
    }

    public void StartMatch() {
		if (PhotonNetwork.IsMasterClient) {
			PhotonNetwork.LoadLevel ("GameIsland");
		}
    }

    public void ResetMatchStartTime() {
        matchStartTime = -1f;
        PhotonDebugger.IncrementNumberOfMessages("match start time");
        photonView.RPC("SetMatchStartTime", RpcTarget.OthersBuffered, -1f);
    }

    /*
    [PunRPC]
    public void SetMatchStartTime(float startTime) {
        LootRandomizer.chestIndex = 0; // just reset the chest index again to make it a little easier to debug 
        matchStartTime = startTime;
        if (startTime == -1f)
            lobbyUI.cancelCountdown = true;
        else if(PhotonNetwork.Time < startTime)
            StartCoroutine(lobbyUI.CountdownToStart());
    }
    */

    public void ToggleJoinAsSpectator(bool _joinAsSpectator) {
        joinAsSpectator = _joinAsSpectator;
    }

    public int GetTotalPlayers() {
        return totalPlayers;
    }

    public int GetTotalSpectators() {
        return totalSpectators;
    }

    IEnumerator SpectatePlayersAfterTheyLoad() {
        GameObject[] players = GameObject.FindGameObjectsWithTag("Player");

        while (players.Length <= 0) {
            yield return null;

            players = GameObject.FindGameObjectsWithTag("Player");
        }

        //SpectatorController spectatorController = GetComponent<SpectatorController>();
        //spectatorController.SpectateAnyPlayer();
    }

    public void ReturnToLobby() {
        StartCoroutine(TotalDisconnect());
    }

    IEnumerator TotalDisconnect() {
        if (PhotonNetwork.InRoom) {
            PhotonNetwork.LeaveRoom();
        }

        PhotonNetwork.Disconnect();

        while (PhotonNetwork.IsConnected) {
            Debug.Log("waiting");
            yield return null;
        }

        SceneManager.LoadScene(0);
    }
}
