using System.Collections;
using System.Collections.Generic;
using UnityEngine;

#if USING_NETCODE_GO
using Unity.Netcode;
using Unity.Netcode.Transports.UTP;
#endif

using System;

namespace SimplifyXR {

    public class RuntimeNetworkManager : IRuntimeNetworkLibrary
    {
        public string[] supportedPackages = {
            "NetCode for GameObjects" };

        public INetworkingLibrary GetNetworkingLibrary()
        {

#if USING_NETCODE_GO
            var networkLibrary = new NetCodeWrapper();
            return networkLibrary;
#else
                      SimplifyXRDebug.SimplifyXRLog(SimplifyXRDebug.Type.Error,
                                "No networking libary installed to use Networking Directives.  " +
                                "Please install a compatible Networking package from the Package Manager."  
                                + "Supported Pacakges include : " + string.Join(",", supportedPackages));
                                            return null;
#endif

        }
    }



#if USING_NETCODE_GO

    public class NetCodeWrapper : INetworkingLibrary
    {
        Unity.Netcode.NetworkManager networkManager;
        UnityTransport unityTransport;

        public event Action<object> OnClientConnected;
        public event Action<object> OnClientDisconnected;
        public event Action OnServerStarted;
        public event Action OnNetworkTransportFailure;

        public NetCodeWrapper()
        {

            networkManager =
               Unity.Netcode.NetworkManager.Singleton;
            if (networkManager == null) networkManager =
                    GameObject.FindObjectOfType<Unity.Netcode.NetworkManager>();

            unityTransport =
                networkManager?.GetComponent<UnityTransport>();

            DetachEvents();
            AttachEvents();
        }

        public void AttachEvents()
        {
            networkManager.OnClientConnectedCallback += ClientConnected;
            networkManager.OnClientDisconnectCallback += ClientDisconnected;
            networkManager.OnServerStarted += ServerStarted;
            networkManager.OnTransportFailure += NetworkTransportFailure;
        }

        public void DetachEvents()
        {
            networkManager.OnClientConnectedCallback -= ClientConnected;
            networkManager.OnClientDisconnectCallback -= ClientDisconnected;
            networkManager.OnServerStarted -= ServerStarted;
            networkManager.OnTransportFailure -= NetworkTransportFailure;
        }

        public void ClientConnected(ulong data)
        {
            OnClientConnected?.Invoke(data);
        }

        public void ClientDisconnected(ulong data)
        {
            OnClientDisconnected?.Invoke(data);
        }


        public void Disconnect()
        {
            networkManager?.Shutdown();
        }

        public string GetIPAddress(bool isLocal)
        {
            throw new System.NotImplementedException();
        }


        public void SetNetworkIP(string ip)
        {

            if (unityTransport)
                unityTransport.ConnectionData.Address = ip;
        }

        public void StartClient()
        {
            networkManager?.StartClient();
        }

        public void StartHost()
        {
            networkManager?.StartHost();
        }

        public void ClientConnected(object data)
        {
            throw new NotImplementedException();
        }

        public void ClientDisconnected(object data)
        {
            throw new NotImplementedException();
        }

        public void ServerStarted()
        {
            OnServerStarted?.Invoke();
        }

        public void NetworkTransportFailure()
        {
            OnNetworkTransportFailure?.Invoke();
        }

        public void SetNetworkPort(string port)
        {
            if (unityTransport)
                unityTransport.ConnectionData.Port = ushort.Parse(port);
        }

        public string GetNetworkPort()
        {
            if (unityTransport)
            {
                return unityTransport.ConnectionData.Port.ToString();
            }
            else { return null; }

        }

        public List<ulong> GetConnectedClients()
        {
            return networkManager.ConnectedClientsIds as List<ulong>;
        }

        public void DisconnectClient(ulong clientId)
        {
            networkManager.DisconnectClient(clientId);
        }
    }

#endif

}

