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

%try-module json
%define NoJson
%endtry

%requires ../../../../qlib/QUnit.qm
%requires ../../../../qlib/Mime.qm
%requires ../../../../qlib/ConnectionProvider
%requires ../../../../qlib/Logger.qm
%requires ../../../../qlib/HttpServerUtil.qm
%requires ../../../../qlib/RestClient.qm
%ifndef NoJson
%requires ../../../../qlib/ZeyosRestClient.qm
%endif
%requires ../../../../qlib/HttpServer.qm

%requires qore >= 0.9.11

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

%disable-warning deprecated

%exec-class ZeyosTest

%ifdef NoJson
class ZeyosRestClient {
    constructor() {
        remove argv;
        throw "NO-MODULE";
    }
    auto methodGate() {
        remove argv;
    }
    auto get() {
        remove argv;
    }
}
class ZeyosRestConnection inherits ZeyosRestClient {
    auto methodGate() {
        remove argv;
    }
}
%endif


class FakeZeyosRestHandler inherits AbstractHttpRequestHandler {
    private {
        string input;
        string mime;
    }

    constructor(string mime, string input) {
        self.mime = mime;
        self.input = input;
    }

    hash<auto> handleRequest(hash cx, hash hdr, *data body) {
        #printf("cx: %N\nhdr: %N\nbody: %N\n", cx, hdr, body);
        if (cx.raw_path =~ /^\/?.+\/auth\/v1\/login$/) {
            return makeResponse({"Content-Type": MimeTypeJson}, 200, "{\"token\": \"token\"}");
        }
        if (cx.raw_path =~ /^\/?.+\/auth\/v1\/logout$/) {
            return makeResponse({"Content-Type": MimeTypeJson}, 200, "OK");
        }
        if (!hdr."authorization") {
            return makeResponse(400, "Missing authorization header");
        }
        if (hdr."authorization" != "Bearer token") {
            return makeResponse(401, "Unauthorized, invalid token");
        }
        if (hdr.method == "GET") {
            return makeResponse(("Content-Type": mime), 200, input);
        }
        if (hdr.method == "PUT") {
            return makeResponse(("Content-Type": mime), 200, input);
        }
    }
}

const VALUE_JSON = {
    "input": "{\"foo\":{\"bar\":1}}",
    "output": {"foo": {"bar": 1}},
};

class ZeyosTest inherits QUnit::Test {
    private {
        HttpServer m_http;
        int port;

        ZeyosRestClient zeyosRestClient;
    }

    constructor() : Test("ZeyosTest", "1.0") {
        addTestCase("zeyos.com REST", \zeyosRestClientRestTests());
        addTestCase("negative tests", \negativeTest());
        addTestCase("connection tests", \connectionTest());
        set_return_value(main());
    }

    globalSetUp() {
        Logger logger("test", LoggerLevel::getLevelInfo());
        if (m_options.verbose > 2) {
            logger.addAppender(new StdoutAppender());
        }
        hash<HttpServerOptionInfo> http_opts = <HttpServerOptionInfo>{
            "logger": logger,
            "debug": True,
        };
        m_http = new HttpServer(http_opts);
        m_http.setHandler("/api/v1/actionsteps", "/api/v1/actionsteps",
                          MimeTypeJson, new FakeZeyosRestHandler(MimeTypeJson, VALUE_JSON.input));
        port = m_http.addListener(<HttpListenerOptionInfo>{"service": 0}).port;

        try {
            zeyosRestClient = new ZeyosRestClient({"url": "http://test1:test2@localhost:" + port, "appsecret": "a", "instance": "x"});
        } catch (hash<ExceptionInfo> ex) {
            if (ex.err == "REST-RESPONSE-ERROR" || ex.err == "NO-MODULE") {
                printf("no client support: %s: %s\n", ex.err, ex.desc);
            } else {
                rethrow;
            }
        }
    }

    globalTearDown() {
        delete zeyosRestClient;
        delete m_http;
    }

    zeyosRestClientRestTests() {
        if (!zeyosRestClient) {
            testSkip("no zeyos.com connection");
        }

        hash<auto> action_data = {
            "name": "Action name 1",
            "description": "description",
            "effort": 48,
            "actionnum": 7771,
            "status": 0,
        };

        hash<auto> response = zeyosRestClient.put("/api/v1/actionsteps", action_data);
        testAssertionValue("/api/v1/actionsteps", response.body, VALUE_JSON.output);
    }

    negativeTest() {
        if (!zeyosRestClient) {
            testSkip("no client support");
        }

        assertThrows("ZEYOSRESTCLIENT-ERROR", sub () {new ZeyosRestClient({"url": "http://localhost:" + port});});
        ZeyosRestClient zeyosRest({"url": "http://localhost:" + port, "token": "asdsad"});
        assertThrows("REST-RESPONSE-ERROR", \zeyosRest.get(), "/api_json");
    }

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

        string url = "http://user:pass@localhost:" + port;
        ZeyosRestConnection zeyosrc("test", "test", url, NOTHING, {"appsecret": "a", "instance": "x"});
        assertEq(True, zeyosrc instanceof ZeyosRestConnection);

        ZeyosRestClient client = zeyosrc.get(False);
        assertEq(True, client instanceof ZeyosRestClient);
    }

}
