using System.Diagnostics;
using System.Net;
using System.Net.Quic;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;

namespace Quic
{
    internal class Program
    {
        static async Task Main(string[] args)
        {
            Console.Title = "Server";
            var options = new QuicListenerOptions()
            {
                ListenEndPoint = new IPEndPoint(IPAddress.IPv6Loopback, 3663),
                ApplicationProtocols = new() { new SslApplicationProtocol("jiri") },
                ConnectionOptionsCallback = (connection, helloInfo, cancellationToken) =>
                {
                    return ValueTask.FromResult(new QuicServerConnectionOptions()
                    {
                        ServerAuthenticationOptions = new SslServerAuthenticationOptions()
                        {
                            ApplicationProtocols = new() { new SslApplicationProtocol("jiri") },
                            ServerCertificate = new X509Certificate(Path.Join(Path.GetDirectoryName(Environment.ProcessPath), "cert.p12"), "password"),
                        },
                        DefaultStreamErrorCode = 0x3FFFFFFFFFFFFFFF,
                        DefaultCloseErrorCode = 0x100,
                    });
                },
            };
            await using (var listener = await QuicListener.ListenAsync(options))
            {
                Console.WriteLine("Ready.");
                while (true)
                {
                    _ = Process(await listener.AcceptConnectionAsync());
                }
            }
        }

        static async Task Process(QuicConnection connection)
        {
            await using (var stream = await connection.AcceptInboundStreamAsync())
            {
                var buffer = new byte[1024];
                try
                {
                    while (true)
                    {
                        await stream.ReadExactlyAsync(buffer.AsMemory(0..1));
                        var data = buffer.AsMemory(0..buffer[0]);
                        await stream.ReadExactlyAsync(data);
                        Console.WriteLine(Encoding.UTF8.GetString(data.Span));
                    }
                }
                catch (EndOfStreamException)
                {
                    Console.WriteLine("Client done.");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }
        }
    }
}