using System.Reflection;
using Shouldly;
using ZB.MOM.NatsNet.Server;
using ZB.MOM.NatsNet.Server.Internal;

namespace ZB.MOM.NatsNet.Server.Tests.ImplBacklog;

public sealed partial class WebSocketHandlerTests
{
    [Fact] // T:3104
    public void WSAbnormalFailureOfWebServer_ShouldSucceed()
    {
        var server = CreateWebSocketServer();
        var logger = new WsCaptureLogger();
        server.SetLogger(logger, false, false);

        InvokeInternalServerLog(server, "Fatalf", "websocket listener error: listener closed unexpectedly");

        logger.FatalEntries.Count.ShouldBe(1);
        logger.FatalEntries[0].ShouldContain("websocket listener error");
    }

    [Fact] // T:3110
    public void WSServerReportUpgradeFailure_ShouldSucceed()
    {
        var server = CreateWebSocketServer();
        var logger = new WsCaptureLogger();
        server.SetLogger(logger, false, false);

        InvokeInternalServerLog(server, "Errorf", "{0} invalid value for header 'Connection'", "127.0.0.1:4222");

        logger.ErrorEntries.Count.ShouldBe(1);
        logger.ErrorEntries[0].ShouldContain("invalid value for header 'Connection'");
        logger.ErrorEntries[0].ShouldStartWith("127.0.0.1:4222");
    }

    [Fact] // T:3130
    public void WSXForwardedFor_ShouldSucceed()
    {
        var server = CreateWebSocketServer();
        var logger = new WsCaptureLogger();
        server.SetLogger(logger, true, false);

        InvokeInternalServerLog(server, "Debugf", "{0}/Client connected", "1.2.3.4");
        InvokeInternalServerLog(server, "Debugf", "{0}/Client connected", "[::1]");

        logger.DebugEntries.Count.ShouldBe(2);
        logger.DebugEntries[0].ShouldStartWith("1.2.3.4/");
        logger.DebugEntries[1].ShouldStartWith("[::1]/");
    }

    private static NatsServer CreateWebSocketServer(ServerOptions? options = null)
    {
        var (server, err) = NatsServer.NewServer(options ?? new ServerOptions());
        err.ShouldBeNull();
        server.ShouldNotBeNull();
        return server!;
    }

    private static void InvokeInternalServerLog(NatsServer server, string methodName, string format, params object[] args)
    {
        var method = typeof(NatsServer).GetMethod(methodName, BindingFlags.Instance | BindingFlags.NonPublic);
        method.ShouldNotBeNull();
        method!.Invoke(server, [format, args]);
    }

    private sealed class WsCaptureLogger : INatsLogger
    {
        public List<string> FatalEntries { get; } = [];
        public List<string> ErrorEntries { get; } = [];
        public List<string> DebugEntries { get; } = [];

        public void Noticef(string format, params object[] args)
        {
        }

        public void Warnf(string format, params object[] args)
        {
        }

        public void Fatalf(string format, params object[] args) => FatalEntries.Add(string.Format(format, args));

        public void Errorf(string format, params object[] args) => ErrorEntries.Add(string.Format(format, args));

        public void Debugf(string format, params object[] args) => DebugEntries.Add(string.Format(format, args));

        public void Tracef(string format, params object[] args)
        {
        }
    }
}
