﻿using System;
using BeardedManStudios.Forge.Networking.Unity;
using Dissonance.Networking;
using UnityEngine;

namespace Dissonance.Integrations.ForgeNetworkingRemastered
{
    public class ForgeRemasteredCommsNetwork
        : BaseCommsNetwork<ForgeRemasteredServer, ForgeRemasteredClient, ForgeRemasteredPeer, Unit, Unit>
    {
        #region fields and properties
        [SerializeField] private int _voiceDataChannelToServer = 57729876;
        [SerializeField] private int _systemMessagesChannelToServer = 57729877;
        [SerializeField] private int _voiceDataChannelToClient = 57729878;
        [SerializeField] private int _systemMessagesChannelToClient = 57729879;

        public int VoiceDataChannelToServer
        {
            get { return _voiceDataChannelToServer; }
        }

        public int SystemMessagesChannelToServer
        {
            get { return _systemMessagesChannelToServer; }
        }

        public int VoiceDataChannelToClient
        {
            get { return _voiceDataChannelToClient; }
        }

        public int SystemMessagesChannelToClient
        {
            get { return _systemMessagesChannelToClient; }
        }
        #endregion

        protected override ForgeRemasteredClient CreateClient(Unit connectionParameters)
        {
            return new ForgeRemasteredClient(this);
        }

        protected override ForgeRemasteredServer CreateServer(Unit connectionParameters)
        {
            return new ForgeRemasteredServer(this);
        }

        protected override void Update()
        {
            // Check is Dissonance is ready
            if (IsInitialized)
            {
                // Check if the HLAPI is ready
                var networkActive = NetworkManager.Instance.Networker.IsConnected && (NetworkManager.Instance.IsServer || true);//NetworkManager.Instance.IsClient);
                if (networkActive)
                {
                    // Check what mode the HLAPI is in (is if it a server, is it a client?)
                    var server = NetworkManager.Instance.IsServer;
                    var client = true;// NetworkManager.Instance.IsClient;

                    // Check what mode Dissonance is in, if they're different then call the correct method
                    if (Mode.IsServerEnabled() != server || Mode.IsClientEnabled() != client)
                    {
                        // HLAPI is server and client, so run as a non dedicated host (passing in the correct parameters, in this case nothing)
                        if (server && client)
                            RunAsHost(Unit.None, Unit.None);

                        // HLAPI is just a server, so run as a dedicated host
                        else if (server)
                            RunAsDedicatedServer(Unit.None);

                        // HLAPI is just a client, so run as a client
                        else if (client)
                            RunAsClient(Unit.None);
                    }
                }
                else if (Mode != NetworkMode.None)
                {
                    //Network is not active, so make sure Dissonance is not active too
                    Stop();
                }
            }

            base.Update();
        }

        internal bool PreprocessPacketToClient(ArraySegment<byte> packet, ForgeRemasteredPeer dest)
        {
            //This should never even be called if this peer is not the host!
            if (Server == null)
                throw Log.CreatePossibleBugException("server packet preprocessing running, but this peer is not a server", "55F5F5D8-8E30-4810-8453-C5D13915118A");

            //If there is no local client (e.g. this is a dedicated server) then there can't possibly be loopback
            var client = Client;
            if (client == null)
                return false;

            //Is this loopback?
            if (!dest.Equals(new ForgeRemasteredPeer(NetworkManager.Instance.Networker.Me)))
                return false;

            //This is loopback!
            client.NetworkReceivedPacket(packet);

            return true;
        }

        internal bool PreprocessPacketToServer(ArraySegment<byte> packet)
        {
            //I have no idea if Forge handles loopback. Whether it does or does not isn't important though - it's more
            //efficient to handle the loopback special case directly instead of passing through the entire network system!

            //This should never even be called if this peer is not a client!
            var client = Client;
            if (client == null)
                throw Log.CreatePossibleBugException("client packet processing running, but this peer is not a client", "DC545FE4-4F5E-4DEB-B441-CFC847140477");

            //Is this loopback?
            if (Server == null)
                return false;

            //This is loopback!
            //Since this is loopback destination == source (by definition)
            Server.NetworkReceivedPacket(new ForgeRemasteredPeer(NetworkManager.Instance.Networker.Me), packet);

            return true;
        }
    }
}
