#include <drogon/drogon.h>
#include <jsoncpp/json/json.h>

#include "qcommsy/libcommsy.hpp"

using namespace drogon;


int main() {
    // Register handlers
    app().registerHandler("/fetchList?url={serverUrl}&sid={sid}&room={room}&startId={startId}&maxPosts={maxPosts}",
                          [](const HttpRequestPtr& /*req*/, std::function<void (const HttpResponsePtr &)> &&callback,
                          const std::string &serverUrl, const std::string &sid, const std::string &room, const std::string &startId, std::string maxPosts)
        {
            if (maxPosts.empty()) {
                maxPosts = "0";
            }

            // Load data from server
            libCommsy *connection = nullptr;
            std::string resStr = "unknown";
            auto resCode = HttpStatusCode::k500InternalServerError;
            try {
                connection = new libCommsy(serverUrl, sid, room, startId, std::stoull(maxPosts));
                resStr = "ok";
                resCode = HttpStatusCode::k200OK;
            } catch (libCommsy::invalidRoomError&) {
                resStr = "invalidRoom";
                resCode = HttpStatusCode::k404NotFound;
            } catch (libCommsy::invalidSIDError&) {
                resStr = "invalidSid";
                resCode = HttpStatusCode::k403Forbidden;
            } catch (libCommsy::connectionFailError&) {
                resStr = "invalidUrl";
                resCode = HttpStatusCode::k502BadGateway;
            } catch (std::invalid_argument&) {
                resStr = "invalidNumber";
                resCode = HttpStatusCode::k400BadRequest;
            }

            // Generate JSON
            Json::Value json;
            json["result"] = resStr;
            if (resCode == 200) {
                json["numposts"] = static_cast<unsigned int>(connection->numposts);
                json["posts"] = Json::arrayValue;
                for (const auto& rawPost : connection->posts) {
                    Json::Value jsonPost;
                    // Get basic details
                    jsonPost["name"] = rawPost.name;
                    jsonPost["meta"] = rawPost.meta;
                    jsonPost["taskState"] = rawPost.taskState;
                    jsonPost["url"] = rawPost.url;
                    jsonPost["id"] = rawPost.id;
                    jsonPost["files"] = Json::arrayValue;
                    // Get files
                    for (const auto& rawFile : rawPost.files) {
                        Json::Value jsonFile;
                        jsonFile["name"] = rawFile.name;
                        jsonFile["url"] = rawFile.url;
                        jsonPost["files"].append(jsonFile);
                    }
                    // Append to posts array
                    json["posts"].append(jsonPost);
                }
            }
            auto resp = HttpResponse::newHttpJsonResponse(json);
            resp->setStatusCode(resCode);
            callback(resp);

            // Clean up
            if (connection) {
                delete connection;
            }
        }, {Get}
    );


    // Start server
    app().setLogPath("./")
         .setLogLevel(trantor::Logger::kWarn)
         .addListener("0.0.0.0", 8000)
         .setThreadNum(16)
         //.enableRunAsDaemon()
         .run();
}