#!/usr/bin/env qore
# -*- mode: qore; indent-tabs-mode: nil -*-

%new-style
%enable-all-warnings
%require-types
%strict-args

%requires ../../../../qlib/Util.qm
%requires ../../../../qlib/QUnit.qm
%requires ../../../../qlib/Logger.qm
%requires ../../../../qlib/HttpServerUtil.qm
%requires ../../../../qlib/HttpServer.qm
%requires ../../../../qlib/WebSocketUtil.qm
%requires ../../../../qlib/ConnectionProvider
%requires ../../../../qlib/WebSocketHandler.qm
%requires ../../../../qlib/WebSocketClient.qm
%requires ../../../../qlib/SewioWebSocketClient.qm

%exec-class SewioWebSocketClientTest

%try-module json >= 1.5
%define NoJson
%endtry

class MyWsConnection inherits WebSocketConnection {
    constructor(WebSocketHandler handler) : WebSocketConnection(handler) {
%ifndef NoJson
        map send(make_json($1)), SewioWebSocketClientTest::Data;
%endif
    }
}

class MyWsHandler inherits WebSocketHandler {
    WebSocketConnection getConnectionImpl(hash cx, hash hdr, string cid) {
        return new MyWsConnection(self);
    }
}

class SewioWebSocketClientTest inherits QUnit::Test {
    public {
        HttpServer mServer;
        MyWsHandler wsHandler();
        int port;

        const Data = (
            "test1",
            "test2",
            "test3",
        );
    }

    constructor() : Test("SewioWebSocketClientTest", "1.0") {
        addTestCase("SewioWebSocketClient tests", \sewioWebSocketClientTests());
        addTestCase("SewioWebSocketConnection tests", \sewioWebSocketConnectionTests());

        Logger logger("test", LoggerLevel::getLevelInfo());
        if (m_options.verbose > 2) {
            logger.addAppender(new StdoutAppender());
        }
        hash<HttpServerOptionInfo> http_opts = <HttpServerOptionInfo>{
            "logger": logger,
            "debug": True,
        };
        mServer = new HttpServer(http_opts);
        mServer.setHandler("ws-handler", "", NOTHING, wsHandler);
        mServer.setDefaultHandler("ws-handler", wsHandler);
        port = mServer.addListener(<HttpListenerOptionInfo>{"service": 0}).port;

        set_return_value(main());

        mServer.stop();
    }

    sewioWebSocketClientTests() {
%ifdef NoJson
        testSkip("no json module");
%endif

        list l = ();
        Counter c(1);
        code cb = sub (*data msg) {
            if (msg) {
                l += msg;
                if (l.size() == Data.size())
                    c.dec();
            }
        };
        hash opts = (
            "url": "sewiows://localhost:" + port,
            "apikey": "x",
            "log": \log(),
            "errlog": \log(),
            "debuglog": \log(),
        );
        SewioWebSocketClient wsc(cb, opts);
        wsc.connect();
        c.waitForZero();
        wsc.disconnect();
        delete wsc;

        assertEq(Data, l);
    }

    sewioWebSocketConnectionTests() {
        string url = "sewiows://localhost:8080";
        SewioWebSocketConnection swsc("test", "test", url, {"monitor": True}, ("apikey": "x"));
        assertEq(True, swsc instanceof SewioWebSocketConnection);

        assertThrows("CONNECTION-OPTION-ERROR", sub () { SewioWebSocketConnection swsc1("test", "test", url); });
    }

    private log(string str) {
        if (m_options.verbose > 2)
            vprintf(str + "\n", argv);
    }
}
