#ifndef REMOTE_SERVER_H
#define REMOTE_SERVER_H

#include <Communicate.h>
#include <InfoCommunicate.hpp>

#include <Util.h>
#include <array>
#include <chrono>
#include <cstdint>
#include <memory>
#include <shared_mutex>
#include <thread>
#include <unordered_map>
#include <wx/event.h>
#include <wx/evtloop.h>
#include <wx/socket.h>
#include <wx/wx.h>

using highClock_t = std::chrono::time_point<std::chrono::high_resolution_clock>;
using sockPtr = std::shared_ptr<wxSocketBase>;
struct TranClient {
    sockPtr wxSock;
    MutBuffer buffer;
    int64_t onlineTime;
    std::string name;
    highClock_t lastRecvTime;
    std::array<char, GBUFFER_SIZE> buf;
};

class RelayServer : public wxEvtHandler
{
public:
    RelayServer();

public:
    bool Init(const wxString& ip, unsigned short port);
    int Run();

private:
    void OnServerEvent(wxSocketEvent& event);
    void thClientThread(const std::shared_ptr<wxSocketBase>& wxSock, const wxString& id);
    bool Forword(const sockPtr& wxSock, FrameBuffer* buf);
    void ReplyRequest(const sockPtr& wxSock, FrameBuffer* frame);
    void ClearClient(const wxString& id);

private:
    bool RpyOnline(const sockPtr& wxSock, FrameBuffer* frame);
    bool RpyForwordFailed(const sockPtr& wxSock, FrameBuffer* frame);

private:
    template <typename T>
    bool Send(const sockPtr& wxSock, const T& info, FrameBufferType type, const std::string& fid, const std::string& tid)
    {
        std::stringstream ss;
        cereal::BinaryOutputArchive archive(ss);
        archive(info);

        auto buf = std::make_shared<FrameBuffer>();
        buf->fid = fid;
        buf->tid = tid;
        std::swap(buf->fid, buf->tid);

        buf->dataConst = ss.view().data();
        buf->len = ss.str().size();
        buf->dataType = type;

        return Send(wxSock, buf.get());
    }
    bool Send(const sockPtr& wxSock, FrameBuffer* buf);

private:
    bool thRun_{false};
    std::string strID_;
    wxWindowID serverId_;
    std::shared_mutex clientsMutex_;
    std::unique_ptr<wxSocketServer> server_;
    std::unordered_map<wxString, std::thread> threads_;
    std::unordered_map<wxString, std::shared_ptr<TranClient>> clients_;
};

#endif   // REMOTE_SERVER_H