#nullable enable
using IGP.UnitySDK.Core;
using IGP.UnitySDK.Models;

namespace IGP.UnitySDK
{
    internal interface IIGPDataPlaneTransport
    {
        IGPDataPlaneMode Mode { get; }
        bool IsConnected { get; }
        bool IsAlive { get; }
        IGPRTTStats? RTTStats { get; }

        void Connect(IGPHostSessionDataPlaneDescriptor descriptor, string roomId, string playerId);
        void Disconnect();
        void Tick();
        void SendMessage(Message message);
        bool TrySendMessage(Message message);
        void SetHeartbeatInterval(float interval);
        void StartHeartbeat(float interval);
        void StopHeartbeat();
    }

    internal static class IGPDataPlaneTransportFactory
    {
        public static IIGPDataPlaneTransport Create(
            IGPHostSessionDataPlaneDescriptor descriptor,
            IGPKcpClient? kcpClient = null)
        {
            switch (descriptor.Mode)
            {
                case IGPHostedDataPlaneMode.DirectKcp:
                    return new IGPDirectKcpDataPlaneTransport(kcpClient);
                default:
                    throw new IGPSDKException($"Unsupported hosted data plane mode: {descriptor.Mode}");
            }
        }
    }

    internal sealed class IGPDirectKcpDataPlaneTransport : IIGPDataPlaneTransport
    {
        private readonly IGPKcpClient client;

        public IGPDirectKcpDataPlaneTransport(IGPKcpClient? client = null)
        {
            this.client = client ?? new IGPKcpClient();
        }

        public IGPDataPlaneMode Mode => IGPDataPlaneMode.DirectKcp;
        public bool IsConnected => client.IsConnected;
        public bool IsAlive => client.IsAlive;
        public IGPRTTStats RTTStats => client.RTTStats;
        public IGPKcpClient Client => client;

        public void Connect(IGPHostSessionDataPlaneDescriptor descriptor, string roomId, string playerId)
        {
            if (string.IsNullOrWhiteSpace(descriptor.Host) ||
                descriptor.Port == 0 ||
                string.IsNullOrWhiteSpace(descriptor.Token))
            {
                throw new IGPSDKException("Invalid hosted direct KCP descriptor");
            }

            client.Connect(descriptor.Host, (int)descriptor.Port, roomId, playerId, descriptor.Token);
        }

        public void Disconnect()
        {
            client.Disconnect();
        }

        public void Tick()
        {
            client.Tick();
        }

        public void SendMessage(Message message)
        {
            client.SendMessage(message);
        }

        public bool TrySendMessage(Message message)
        {
            return client.TrySendMessage(message);
        }

        public void SetHeartbeatInterval(float interval)
        {
            client.HeartbeatInterval = interval;
        }

        public void StartHeartbeat(float interval)
        {
            client.StartHeartbeat(interval);
        }

        public void StopHeartbeat()
        {
            client.StopHeartbeat();
        }
    }
}
