﻿using System.Collections.Generic;
using JLGames.RocketDriver.CSharp.Event;
using JLGames.RocketDriver.Games.RpgMaterial.Common;

namespace JLGames.RocketDriver.Games.NetManager.Virtual
{
    public class VirtualServer : EventDispatcher, IVirtualServerExtension, IVirtualServerProxy, IVirtualServer
    {
        protected struct ProtoHandler
        {
            internal string ProtoId;
            internal VirtualServerDelegate.OnProtoRequestHandler Handler;
        }

        private readonly string m_Name;
        private readonly string m_GroupName;
        protected readonly List<ProtoHandler> m_Extensions = new List<ProtoHandler>();

        public string Name => m_Name;
        public string GroupName => m_GroupName;

        public VirtualServer()
        {
            m_Name = "VirtualServer";
            m_Name = "Default";
        }

        public VirtualServer(string name, string groupName)
        {
            m_Name = name;
            m_GroupName = groupName;
        }

        // IVirtualServer

        public virtual void Startup()
        {
            throw new System.NotImplementedException();
        }

        public virtual void Shutdown()
        {
            throw new System.NotImplementedException();
        }

        public virtual void Reboot()
        {
            Shutdown();
            Startup();
        }

        // INetEntity

        public void Destroy()
        {
            UnregisterExtensions();
        }

        // IVirtualServerExtension

        public void RegisterExtension(string protoId, VirtualServerDelegate.OnProtoRequestHandler onProtoRequestHandler)
        {
            m_Extensions.Add(new ProtoHandler {ProtoId = protoId, Handler = onProtoRequestHandler});
        }

        public void UnregisterExtension(string protoId)
        {
            for (var index = m_Extensions.Count - 1; index >= 0; index--)
            {
                if (m_Extensions[index].ProtoId == protoId)
                {
                    m_Extensions.RemoveAt(index);
                    return;
                }
            }
        }

        public void UnregisterExtensions()
        {
            m_Extensions.Clear();
        }

        // IVirtualServerProxy
        public void OnRequest(string protoId, object data)
        {
            for (var index = 0; index < m_Extensions.Count; index++)
            {
                if (m_Extensions[index].ProtoId == protoId)
                {
                    m_Extensions[index].Handler.Invoke(this, protoId, data);
                    return;
                }
            }

            ResponseToClient(protoId, VirtualResultCodes.Undefined, protoId);
        }

        // IResponseServer

        public void ResponseToClient(string protoId, int rsCode, object data = null)
        {
            DispatchEvent(VirtualServerEvents.EventResponse, new VirtualServerResponse {Pid = protoId, RsCode = rsCode, Data = data});
        }

        // INotifyServer

        public void NotifyToClient(string protoId, object data = null)
        {
            DispatchEvent(VirtualServerEvents.EventNotify, new VirtualServerNotify {Pid = protoId, Data = data});
        }

        internal void NotifyMaterialToClient(string protoId, object data = null)
        {
            DispatchEvent(VirtualServerEvents.EventMaterialNotify, new VirtualServerNotify {Pid = protoId, Data = data});
        }

        // IMaterialNotifyServer

        public void NotifyMaterialEntryUpdate(DataOffset offset)
        {
            if (offset.Id == 0 || offset.Offset == 0) return;
            NotifyMaterialToClient(VirtualServerProtos.ProtoNotifyUserOffset, offset);
        }

        public void NotifyMaterialEntryUpdate(DataNum num)
        {
            if (num.Id == 0) return;
            NotifyMaterialToClient(VirtualServerProtos.ProtoNotifyUserNum, num);
        }

        public void NotifyMaterialEntryUpdate(UserNotifyData notify)
        {
            if (notify.Id == 0) return;
            NotifyMaterialToClient(VirtualServerProtos.ProtoNotifyUserData, notify);
        }

        public void NotifyMaterialEntryUpdate(DataOffset[] offsetArr)
        {
            if (null == offsetArr || offsetArr.Length == 0) return;
            NotifyMaterialToClient(VirtualServerProtos.ProtoNotifyUserOffsets, offsetArr);
        }

        public void NotifyMaterialEntryUpdate(DataNum[] numArr)
        {
            if (null == numArr || numArr.Length == 0) return;
            NotifyMaterialToClient(VirtualServerProtos.ProtoNotifyUserNums, numArr);
        }

        public void NotifyMaterialEntryUpdate(UserNotifyData[] notifyArr)
        {
            if (null == notifyArr || notifyArr.Length == 0) return;
            NotifyMaterialToClient(VirtualServerProtos.ProtoNotifyUserDatas, notifyArr);
        }
    }
}