using System.Reflection;
using AlicizaX;
using Cysharp.Threading.Tasks;
using Fantasy;
using Fantasy.Network;
using Fantasy.Network.Interface;

namespace AlicizaX.Network.Runtime
{
    [UnityEngine.Scripting.Preserve]
    internal sealed class NetworkModule : INetworkModule
    {
        private Scene _scene;
        private Session _session;
        private int _heartInterval;


        public EConnectState ConnectState => _connectState;

        private EConnectState _connectState;
        void IModule.Dispose()
        {
            _scene?.Dispose();
            _session?.Dispose();
        }

        public void SetHeartInterval(int heartInterval)
        {
            _heartInterval = heartInterval;
        }

        public async UniTask Initialize(params Assembly[] assemblies)
        {
            Assembly[] allAssemblies = new Assembly[assemblies.Length + 1];
            for (int i = 0; i < assemblies.Length; i++)
            {
                allAssemblies[i] = assemblies[i];
            }

            allAssemblies[allAssemblies.Length - 1] = typeof(NetworkModule).Assembly;

            await Fantasy.Platform.Unity.Entry.Initialize(allAssemblies);
            _scene = await Scene.Create(SceneRuntimeType.MainThread);
        }

        public void Connect(string remoteAddress, NetworkProtocolType networkProtocolType, bool isHttps)
        {
            _session = _scene.Connect(remoteAddress, networkProtocolType, OnConnectComplete, OnConnectFail, OnConnectDisconnect, isHttps);
        }

        public async UniTask<T> Call<T>(IRequest request, long routeId = 0) where T : IResponse
        {
            return (T)await _session.Call(request, routeId);
        }

        public void Send(IMessage message, uint rpcId = 0, long routeId = 0)
        {
            _session.Send(message, rpcId, routeId);
        }

        public void Send(IRouteMessage routeMessage, uint rpcId = 0, long routeId = 0)
        {
            _session.Send(routeMessage, rpcId, routeId);
        }


        private void OnConnectComplete()
        {
            _connectState = EConnectState.Connect;
            _session.AddComponent<SessionHeartbeatComponent>().Start(_heartInterval);
            Log.Info("Connect Success");
        }

        private void OnConnectFail()
        {
            _connectState = EConnectState.None;
            Log.Info("Connect Fail");
        }

        private void OnConnectDisconnect()
        {
            _connectState = EConnectState.Disconnect;
            Log.Info("Disconnect");
        }
    }
}
