#pragma once
#include <drogon/DrObject.h>
#include <drogon/HttpAppFramework.h>
#include <drogon/WebSocketConnection.h>
#include <drogon/HttpTypes.h>
#include <trantor/utils/Logger.h>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#define WS_PATH_LIST_BEGIN        \
    static void initPathRouting() \
    {
#define WS_PATH_ADD(path, ...) registerSelf__(path, {__VA_ARGS__})
#define WS_ADD_PATH_VIA_REGEX(regExp, ...) \
    registerSelfRegex__(regExp, {__VA_ARGS__})
#define WS_PATH_LIST_END }
namespace drogon
{
class WebSocketControllerBase : public virtual DrObjectBase
{
  public:
    virtual void handleNewMessage(const WebSocketConnectionPtr &,
                                  std::string &&,
                                  const WebSocketMessageType &) = 0;
    virtual void handleNewConnection(const HttpRequestPtr &,
                                     const WebSocketConnectionPtr &) = 0;
    virtual void handleConnectionClosed(const WebSocketConnectionPtr &) = 0;
    virtual ~WebSocketControllerBase()
    {
    }
};
using WebSocketControllerBasePtr = std::shared_ptr<WebSocketControllerBase>;
template <typename T, bool AutoCreation = true>
class WebSocketController : public DrObject<T>, public WebSocketControllerBase
{
  public:
    static const bool isAutoCreation = AutoCreation;
    virtual ~WebSocketController()
    {
    }
  protected:
    WebSocketController()
    {
    }
    static void registerSelf__(
        const std::string &path,
        const std::vector<internal::HttpConstraint> &constraints)
    {
        LOG_TRACE << "register websocket controller("
                  << WebSocketController<T, AutoCreation>::classTypeName()
                  << ") on path:" << path;
        app().registerWebSocketController(
            path,
            WebSocketController<T, AutoCreation>::classTypeName(),
            constraints);
    }
    static void registerSelfRegex__(
        const std::string &regExp,
        const std::vector<internal::HttpConstraint> &constraints)
    {
        LOG_TRACE << "register websocket controller("
                  << WebSocketController<T, AutoCreation>::classTypeName()
                  << ") on regExp:" << regExp;
        app().registerWebSocketControllerRegex(
            regExp,
            WebSocketController<T, AutoCreation>::classTypeName(),
            constraints);
    }
  private:
    class pathRegistrator
    {
      public:
        pathRegistrator()
        {
            if (AutoCreation)
            {
                T::initPathRouting();
            }
        }
    };
    friend pathRegistrator;
    static pathRegistrator registrator_;
    virtual void *touch()
    {
        return &registrator_;
    }
};
template <typename T, bool AutoCreation>
typename WebSocketController<T, AutoCreation>::pathRegistrator
    WebSocketController<T, AutoCreation>::registrator_;
}  