﻿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 = "2022_06_18";

	public GameObject testPlayer;
	public bool testPlay = false;

    public int maxPlayersPerRoom = 9;
    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;
        LootRandomizer.CurrentChestIndex = 0;

        string token = "us";

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

    public void Connect() 
    {
        if (PhotonNetwork.IsConnected)
        {
            PhotonHashtable playerProperties = new PhotonHashtable() { { "IsSpectator", joinAsSpectator }, { "DisplayName", PersistentData.localPlayerData.username } };
            PhotonNetwork.LocalPlayer.SetCustomProperties(playerProperties);
            PhotonHashtable expectedCustomRoomProperties = new PhotonHashtable() { { joinAsSpectator ? "spectator_slots_availabile" : "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");
        
        PhotonHashtable playerProperties = new PhotonHashtable() { { "IsSpectator", joinAsSpectator } , { "DisplayName", PersistentData.localPlayerData.username } };
        PhotonNetwork.LocalPlayer.SetCustomProperties(playerProperties);
        PhotonHashtable expectedCustomRoomProperties = new PhotonHashtable() { { joinAsSpectator ? "spectator_slots_availabile" : "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)
            {
                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.CurrentChestIndex = 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);
    }
}
