#include <DirectCommunicationClient.hpp>


#include "zmq.hpp"
#include <functional>
#include <memory>
#include <string>
#include <sys/types.h>
#include <thread>
#include <loguru.hpp>
#include <future>


namespace DirectCommunication 
{
    DirectCommunicationClient::DirectCommunicationClient(ushort port, std::string ServerAddress):port_(port),serverAddress_(ServerAddress)
    {

        context_ = zmq::context_t();
        socket_ = zmq::socket_t(context_,zmq::socket_type::client);
        LOG_S(INFO)<< "tcp://"+serverAddress_+":"+std::to_string(port_);

        socket_.connect("tcp://"+serverAddress_+":"+std::to_string(port_));
        isConnected = true;

        socket_.set(zmq::sockopt::rcvtimeo,100);
        socket_.set(zmq::sockopt::sndtimeo,500);

        Worker_ = std::thread(&DirectCommunicationClient::workerFunc_,this);
        stopWorker_ = false;


    }


    DirectCommunicationClient::~DirectCommunicationClient()
    {
       this->disconnect();
    }

    void DirectCommunicationClient::disconnect()
    {   
        sendMessage("CLOSE");

        useHandl_ = false;
        MessageHandle_ = nullptr;
        stopWorker_ = true;
        Worker_.join();

        socket_.close();
        isConnected = false;
        
    }

     void DirectCommunicationClient::registerMessageCallback(std::function<void(std::string)> MessageHandle)
    {
        MessageHandle_ = MessageHandle;
        useHandl_ = true;
    }

    void  DirectCommunicationClient::sendMessage(std::string msg)
    {
       
        zmq::message_t zmqMsg(msg.begin(),msg.end());
        
        if (isConnected == true) {
            socket_.send(zmqMsg,zmq::send_flags::dontwait);
        }
            
        
    }

    std::string  DirectCommunicationClient::getLatestMessage()
    {
        if (receivedMessages_.size() > 0) 
        {   
            std::string msg; 
            receivedMessages_.get(msg);
            return msg;
        }
        return "NULL";
    }

    void DirectCommunicationClient::workerFunc_()
    {
        
        while (stopWorker_ == false) 
        {   
            zmq::message_t msg;
            auto recv = socket_.recv(msg,zmq::recv_flags::none);

            if (recv > 0) 
            {
                isConnected = true;
                if (msg.to_string() == "CLOSE") 
                {
                    isConnected = false;
                    socket_.disconnect("tcp://"+serverAddress_+":"+std::to_string(port_));

                }else 
                {
                    if (MessageHandle_ == nullptr) 
                    {   
                        receivedMessages_.addElement(msg.to_string());
                        // MessageHandle_(msg.to_string());
                    }
                    else 
                    {   
                        if (useHandl_ == true) 
                        {
                             auto i = std::async(std::launch::async, MessageHandle_, msg.to_string());   
                        }
    
                        
                    }
                }


            }
        }

    }




}