#nullable enable
using IGP.UnitySDK.Models;
using IGP.UnitySDK;
using System.Collections.Generic;
using IGP.Multiplayer.Core;
using IGP.Multiplayer.Models;

namespace IGP.Multiplayer
{
    internal interface IIGPDataPlaneTransport
    {
        IGPDataPlaneMode Mode { get; }
        bool IsConnected { get; }
        bool IsAlive { get; }
        bool IsWritable { get; }
        IGPRTTStats? RTTStats { get; }
        IGPKcpTransportStats TransportStats { get; }

        void Connect(IGPHostSessionDataPlaneDescriptor descriptor, string roomId, string playerId);
        void Disconnect();
        void Tick();
        IGPTransportSendResult TrySendMessages(IReadOnlyList<Message> messages, bool isControl);
    }

    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 bool IsWritable => client.IsWritable;
        public IGPRTTStats RTTStats => client.RTTStats;
        public IGPKcpTransportStats TransportStats => client.TransportStats;
        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 IGPTransportSendResult TrySendMessages(IReadOnlyList<Message> messages, bool isControl)
        {
            return client.TrySendMessages(messages, isControl);
        }
    }
}
