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

namespace Dissonance.Integrations.ForgeNetworkingRemastered
{
    public class ForgeRemasteredServer
        : BaseServer<ForgeRemasteredServer, ForgeRemasteredClient, ForgeRemasteredPeer>
    {
        private readonly ForgeRemasteredCommsNetwork _net;
        private readonly BMSByte _sendBuffer = new BMSByte();

        private NetWorker _networker;

        public ForgeRemasteredServer(ForgeRemasteredCommsNetwork net)
        {
            _net = net;
        }

        public override void Connect()
        {
            _networker = NetworkManager.Instance.Networker;
            _networker.binaryMessageReceived += ForgeNetworkMessageReceived;
            _networker.playerDisconnected += ForgePlayerDisconnected;

            if (!(_networker is BaseUDP))
                Log.Error("Forge Networking Remastered client is not a UDP client! Dissonance Voice will still function but quality will be severly degraded");

            base.Connect();
        }

        private void ForgePlayerDisconnected(NetworkingPlayer player)
        {
            ClientDisconnected(new ForgeRemasteredPeer(player));
        }

        public override void Disconnect()
        {
            base.Disconnect();
            NetworkManager.Instance.Networker.messageReceived -= ForgeNetworkMessageReceived;
            _networker.playerDisconnected -= ForgePlayerDisconnected;
        }

        #region receive
        private void ForgeNetworkMessageReceived(NetworkingPlayer player, FrameStream frame)
        {
            if (frame.GroupId != _net.VoiceDataChannelToServer && frame.GroupId != _net.SystemMessagesChannelToServer)
                return;

            NetworkReceivedPacket(new ForgeRemasteredPeer(player), new ArraySegment<byte>(frame.StreamData.byteArr, frame.StreamData.StartPointer, frame.StreamData.Size));
        }

        protected override void ReadMessages()
        {
            //messages are received in event handler, no work is needed here
        }
        #endregion

        #region send
        private void Send(ForgeRemasteredPeer peer, ArraySegment<byte> packet, int channel, bool reliable)
        {
            if (_net.PreprocessPacketToClient(packet, peer))
                return;

            _sendBuffer.Clear();
            _sendBuffer.BlockCopy(packet.Array, packet.Offset, packet.Count);

            var message = new Binary(
                _networker.Time.Timestep,
                _networker is BaseTCP,
                _sendBuffer,
                Receivers.Target,
                channel,
                _networker is BaseTCP
            );

            var udp = _networker as UDPServer;
            if (udp != null)
                udp.Send(peer.NetworkingPlayer, message, reliable);
            else
                ((TCPServer)_networker).Send(peer.NetworkingPlayer.TcpClientHandle, message);
        }

        protected override void SendUnreliable(ForgeRemasteredPeer connection, ArraySegment<byte> packet)
        {
            Send(connection, packet, _net.SystemMessagesChannelToClient, false);
        }

        protected override void SendReliable(ForgeRemasteredPeer connection, ArraySegment<byte> packet)
        {
            Send(connection, packet, _net.SystemMessagesChannelToClient, true);
        }
        #endregion
    }
}
