using Cysharp.Threading.Tasks;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UDB;
using Unity.Netcode;
using Unity.Netcode.Transports.UTP;
using Unity.Networking.Transport;
using Unity.Services.Authentication;
using Unity.Services.Core;
using Unity.Services.Lobbies.Models;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using static Unity.Netcode.NetworkSceneManager;

public class NetworkCoreFactory : NetworkBehaviour
{
    public MatchmakingService matchmakingService;
    public UnityEvent OnLoadEventStarted;
    public UnityEvent OnLoadEventCompleted;

    private bool loadEventCompleted = false;

    #region Unity Methods
    // Called when the script instance is being loaded
    void Start()
	{
        NetworkSceneDirector.instance.OnWillLoadScene += OnWillLoadScene;
        if (NetworkManager.Singleton.IsClient == false && NetworkManager.Singleton.IsServer == false) {
#if UNITY_EDITOR
			StartConnection();
#else
			Debug.Log("Starting Local Connection since we loaded a network scene without networking");
			NetworkManager.Singleton.GetComponent<UnityTransport>().SetConnectionData("127.0.0.1", 7777);
            NetworkManager.Singleton.StartHost();
#endif
        }
	}

    public override void OnNetworkSpawn()
    {
        NetworkManager.Singleton.OnClientConnectedCallback += OnClientConnectedCallback;
        NetworkManager.Singleton.SceneManager.OnLoadEventCompleted += OnEventCompletedDelegateHandler;
    }

    public override void OnDestroy()
    {
        base.OnDestroy();
        if (NetworkSceneDirector.exists) {
            NetworkSceneDirector.instance.OnWillLoadScene -= OnWillLoadScene;
        }
        if (NetworkManager.Singleton != null) {
            NetworkManager.Singleton.OnClientConnectedCallback -= OnClientConnectedCallback;
            if (NetworkManager.Singleton.SceneManager != null) {
                NetworkManager.Singleton.SceneManager.OnLoadEventCompleted -= OnEventCompletedDelegateHandler;
            }
        }
    }
    #endregion

    void OnWillLoadScene()
    {
        ServerWillLoadSceneClientRpc();
    }

    [ClientRpc]
    private void ServerWillLoadSceneClientRpc(ClientRpcParams clientRpcParams = default)
    {
        OnLoadEventStarted?.Invoke();
    }

    void OnClientConnectedCallback(ulong id)
    {
        if (loadEventCompleted) {
            DoneLoadingClientRpc();
        }
    }

    [ClientRpc]
    private void DoneLoadingClientRpc(ClientRpcParams clientRpcParams = default)
    {
        OnLoadEventCompleted?.Invoke();
    }

    void OnEventCompletedDelegateHandler(string sceneName, LoadSceneMode loadSceneMode, List<ulong> clientsCompleted, List<ulong> clientsTimedOut)
    {
        loadEventCompleted = true;
		OnLoadEventCompleted?.Invoke();
    }

    async void StartConnection()
    {
		await UniTask.Delay(1000);
		await Authentication.Login();

		DebugStartClient();
	}

	async void DebugStartHost()
	{
		Debug.Log("Starting Debug Host");
		MatchmakingService.LobbyData data;
		data.Name = System.Environment.MachineName;
		data.MaxPlayers = 10;
		data.Difficulty = 0;
		data.Type = 0;
        data.MatchId = "";

		await matchmakingService.CreateLobbyWithAllocation(data);

		// Starting the host immediately will keep the relay server alive
		NetworkManager.Singleton.StartHost();
    }

	async void DebugStartClient()
    {
		var allLobbies = await matchmakingService.GatherLobbies();

		foreach (var lobby in allLobbies) {
			if (lobby.Name == System.Environment.MachineName) {
                Debug.Log("Found Debug Lobby");
                JoinLobby(lobby);
				return;
			}
		}

		DebugStartHost();
	}

	async void JoinLobby(Lobby lobby)
	{
        if (NetworkManager.Singleton.IsClient || NetworkManager.Singleton.IsServer) {
            Debug.Log("Shutting Down Previous Match");
            NetworkManager.Singleton.Shutdown();
        }

        await matchmakingService.JoinLobbyWithAllocation(lobby.Id);

		NetworkManager.Singleton.StartClient();
		NetworkSceneDirector.instance.OnClientStarted();
    }
}
