﻿using System;
using Dissonance.Networking;
using BNetworking = BeardedManStudios.Network.Networking;

namespace Dissonance.Integrations.ForgeNetworking
{
    public class ForgeCommsNetwork
        : BaseCommsNetwork<ForgeServer, ForgeClient, ForgePeer, Unit, Unit>
    {
        public int VoiceDataChannelToServer = 57729872;
        public int SystemMessagesChannelToServer = 57729873;
        public int VoiceDataChannelToClient = 57729874;
        public int SystemMessagesChannelToClient = 57729875;
        
        protected override ForgeServer CreateServer(Unit details)
        {
            return new ForgeServer(this);
        }

        protected override ForgeClient CreateClient(Unit details)
        {
            return new ForgeClient(this);
        }

        protected override void Update()
        {
            if (IsInitialized)
            {
                if (BNetworking.PrimarySocket != null)
                {
                    if (BNetworking.PrimarySocket.IsServer)
                    {
                        if (Mode != NetworkMode.Host)
                            RunAsHost(Unit.None, Unit.None);
                    }
                    else
                    {
                        if (Mode != NetworkMode.Client)
                            RunAsClient(Unit.None);
                    }
                }
                else
                {
                    if (Mode != NetworkMode.None)
                        Stop();
                }
            }

            base.Update();
        }
        
        public bool PreprocessPacketToClient(ArraySegment<byte> packet, ForgePeer destination, uint channel, bool reliable)
        {
            //Forge does not seem to handle loopback in all situations (when sending to a specific player)
            //This runs before the server sends any packets and if it returns true the packet is not sent.
            //We'll use this to intercept loopback packets and deliver them ourselves.

            //This should never even be called if this peer is not the host!
            if (!Mode.IsServerEnabled())
            {
                Log.Error("Dissonance Forge server packet preprocessing running, but this peer is not a server");
                return false;
            }

            //Is this loopback?
            if (destination.Peer.NetworkId != BNetworking.PrimarySocket.Me.NetworkId)
                return false;

            //This is loopback!

            //Since this is loopback destination == source (by definition)
            Client.NetworkReceivedPacket(data: packet);

            return true;
        }

        public bool PreprocessPacketToServer(ArraySegment<byte> packet, uint channel, bool reliable)
        {
            //Technically this isn't needed, forge handles loopback just fine sending from client -> server
            //However this is slightly more efficient (no point running through all that forge logic when
            //we could just pass a pointer across directly)
            
            //This should never even be called if this peer is not a client!
            if (!Mode.IsClientEnabled())
            {
                Log.Error("Forge client packet preprocessing running, but this peer is not a client");
                return false;
            }

            //Is this loopback?
            if (!Mode.IsServerEnabled())
                return false;

            //This is loopback!

            //Since this is loopback destination == source (by definition)
            Server.NetworkReceivedPacket(source: new ForgePeer(BNetworking.PrimarySocket.Me), data: packet);

            return true;
        }
    }
}
