//
// Created by Ht on 2020/5/8.
//

#ifndef TESTBIN_MisHTTPSERVER_H
#define TESTBIN_MisHTTPSERVER_H

#include <iostream>
#include <vector>

#include <qlibc/qlibc.h>

#include <mgbus/MgDataChannel.h>

#include "QHttpCommon.h"

#include <mgbus/ChannelOperator.h>

namespace jedge {

    //监听http端口
    static const char* midx_base_file_path = "./www";

    const static char* DATA_CHANNEL_HTTP = "http";

    const static int ival_default_http_timeout_ms_ = 10000;

    //并发线程数量
    static const int MGBUS_DATA_HANDLE_THREAD_COUNT = 10;

    using QHttpHandler = std::function<bool (const httplib::Request &httprequest, const qlibc::QData& request, qlibc::QData& response)>;
    using QHttpHandlerMap = std::unordered_map<std::string, httplib::Server::Handler>;

#define AppendHttpPathHandler(targetObj, patten, method) \
    targetObj.addPathHandler((patten),  [this](const httplib::Request & httpreq, const qlibc::QData& request, qlibc::QData& respnose) -> bool { \
        return this->method(httpreq,  request, respnose); \
    })

#define AppendHttpPatternHandler(targetObj, patten, method) \
    targetObj.addPatternHandler((patten),  [this](const httplib::Request & httpreq, const qlibc::QData& request, qlibc::QData& respnose) -> bool { \
        return this->method(httpreq,  request, respnose); \
    })

    class JE_API QHttpServer : public qlibc::QSelfRefObject {
    protected:
        ChannelOperator& opr_;
        httplib::Server* server_;
        std::vector<std::string>  key_order_list_;          //多种规则并存时、规则key的优先级顺序
        QHttpHandlerMap mPathHandlers;
        QHttpHandlerMap mPatternHandlers;
        httplib::Logger mLogger;
        qlibc::QSharedObjectHolder<ifstream> mFileCache;
        string mBasePath;

        int http_timeout_ms_ = ival_default_http_timeout_ms_;

        CMDnsServicePublish *mcmdns_pub_ = nullptr;

        int port_ = -1;

        bool active_ = false;
    public:
        explicit QHttpServer(ChannelOperator& opr);

        ~QHttpServer();

        const string &objId() override;

    protected:
        void addRawHandler(QHttpHandlerMap& target, const string& key, const QHttpHandler& handler, bool ordered = false);

    public:
        void shutdown();

        bool start(int httpPort, const std::string& subnet = "", const std::string& key="");

        void addPathHandler(const string& path, const QHttpHandler& handler);

        void addPatternHandler(const string& pattern, const QHttpHandler& handler);

        void removeAllHanlders();

        virtual bool defaultHandler(const httplib::Request & httpreq, const qlibc::QData& req, qlibc::QData &res);

        bool MisBindHttpPort(const std::string& hostAddr, int httpPort);

        void buildHttpResponse(httplib::Response &response, const qlibc::QData &jrres);

        void buildHttpInputParams(qlibc::QData &jrreq, const httplib::Request &httprequest);

        void setBasePath(const string &basePath);

        const string& getBasePath();

        void findFile(qlibc::QData &response, const string &fileName, const string& mime = "");

        std::shared_ptr<ifstream> getCachedStream(const string &file, bool autoRemove = true);

        void closeCachedStream(const std::shared_ptr<std::ifstream>& fs, const std::string& file = "");

    public:
        static void MimeNameFromExt(const string &ext, string& mime);

        static void MimeNameFromFileName(const std::string &fileName, std::string &mime);

        void
        doAddHttpHandler(const httplib::Server::Handler &httpHandler, QHttpHandlerMap &target, const string &key,
                         bool ordered);

        bool isActive();

        inline void setTimeout(int to_ms) {
            http_timeout_ms_ = to_ms;
        }

        int getCurrentHttpPort() {
            return port_;
        }

    protected:
        void prepareHttpServer();

        bool doCacheFile(const std::string &cacheFile);
    };

}
#endif //TESTBIN_MisHTTPSERVER_H
