

#include "SimControl/SimControl.hpp"

#include "SimCore/Messages/SensorTrack.hpp"
#include "nlohmann/json_fwd.hpp"
#include <fstream>
#include <future>
#include <memory>
#include <queue>
#include <string>
#define CATCH_CONFIG_MAIN
#include "SimControl/PodList.hpp"
#include <catch2/catch.hpp>
#include <loguru.hpp>

#include <Orders/TracklistRequest.hpp>



#include "easywsclient.hpp"
#include <nlohmann/json.hpp>
#include <SimCore/Messages/TracklistUpdate.hpp>
#include <SimCore/Messages/TracklistItem.hpp>

// std::shared_ptr<SimControl::SimControl> sc;
struct HelpMessage{
  std::string IP;
  std::string Port;
  WHISPER::Message msg;
} ;
WHISPER::threadSafeQueue<HelpMessage> Wmsgqueue_in_;

int runSimConntrol(bool *running)
{
    SimControl::SimControl sc(false,"CommandPortChar","5555",SimCore::UtilFunctions::StringToUShort("10000"),"simulator");
    //  sc = std::make_shared<SimControl::SimControl>(false,"CommandPortChar","5555",SimCore::UtilFunctions::StringToUShort("10000"),"simulator");

     while (*running) {

      std::this_thread::sleep_for(std::chrono::milliseconds(100));
    //   LOG_S(INFO)<<*running;
    if (Wmsgqueue_in_.size()> 0)
    {
      auto msg = Wmsgqueue_in_.get();
      sc.sendRecvMessageToClient(msg.IP,msg.Port,msg.msg, true);
    }
    
    } 
    LOG_S(INFO)<<"stopping ";
    sc.stop();
return 0;
}
WHISPER::threadSafeQueue<std::string> msgqueue_in_;
WHISPER::threadSafeQueue<std::string> msgqueue_out_;

// std::queue<std::string> msgqueue_in_;
// std::queue<std::string> msgqueue_out_;



void handle_message(std::string m)
{
        LOG_S(INFO)<<m;
        msgqueue_in_.addElement(m);

}


void wsFunction(bool *running)
{
std::unique_ptr<easywsclient::WebSocket> ws(easywsclient::WebSocket::from_url("ws://localhost:9999/"));


while (*running)
 {
     ws->poll();
    ws->dispatch(handle_message);
    while(msgqueue_out_.size() > 0)
    {
        ws->send(msgqueue_out_.get());
    }

}
        ws->close();

}
double fRand(double fMin, double fMax)
{
    double f = (double)rand() / RAND_MAX;
    return fMin + f * (fMax - fMin);
}
void addTracksToTracklistUpdate(SimCore::TracklistUpdate *update, int amount)
{

  for(int i = 0; i < amount; i++)
  {
     std::string name = "test1-" + std::to_string(i);
    auto track = std::make_shared<SimCore::SensorTrack>(name,SimCore::Kind::EntityKind::SURFACE,SimCore::Side::NEUTRAL);
    SimCore::Position pos;
    double lat =  fRand(-90, 90);
    double lon =  fRand(-180, 180);

    pos.setGeodesicPos( lat,  lon, 0);
    track->setPosition(pos);
    SimCore::TracklistItem item(track);
    update->addTrack(item);
  }



}


std::atomic_bool TracklistRequestReceived;

void serverCallback(std::string msg)
{

  // LOG_S(INFO)<<msg;
  WHISPER::Message Wmsg_(msg);

  switch (Wmsg_.msgType_)
  {
  case WHISPER::MsgType::ORDER:
    {
          Orders::OrderType OrderType = Orders::Order::getType(Wmsg_);
          switch (OrderType)
          {
           case Orders::TRACKLIST_REQUEST:
            {   
                auto TrackListRequest = Orders::TracklistRequest::unpack(Wmsg_);
                if (TrackListRequest == nullptr) 
                {
                  break;
                }
                LOG_S(INFO)<<"tracklist request received";
                TracklistRequestReceived = true;
                break;
            }
        
          }
    break;
    }
  

  }



}

SCENARIO("Testing the the podlist")
{
bool *running = new bool(true);
 std::thread t1(runSimConntrol,running) ;
// auto res = std::async(std::launch::deferred,runSimConntrol,running);
std::this_thread::sleep_for(std::chrono::milliseconds(300));
std::thread t2(wsFunction,running) ;

nlohmann::json j;
j["Data"] = "TEST";

bool gotMessage = false;

msgqueue_out_.addElement(j.dump());


  GIVEN("different Attributes for a Track in different forms")
  { 
    SimCore::Identifier ID_;
        SimCore::Identifier ID1_;

        std::this_thread::sleep_for(std::chrono::milliseconds(500));

  DirectCommunication::DirectCommunicationServer server(5555,ID1_.getUUID());
  server.registerMessageCallback(serverCallback);
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    // auto client = std::make_unique<DirectCommunication::DirectCommunicationClient>(5001,"127.0.0.1",ID_.getUUID());     
    // client->sendMessage("test");
  Orders::TracklistRequest TrackListRequest(ID_,ID1_);

    HelpMessage msg1;
    msg1.IP = "127.0.0.1";
    msg1.Port = "5555";
    msg1.msg = TrackListRequest.buildMessage();
    Wmsgqueue_in_.addElement(msg1);
    WHEN("constructing Track Object with data")
    {
    // std::string response = sc->sendRecvMessageToClient("127.0.0.1","5555",TrackListRequest.buildMessage(),false);
    LOG_S(INFO)<<"sended";
    // LOG_S(INFO)<<Helper.getLatesMessage().msgType_;  
      THEN("check if Track attributes are correct")
      {
        std::this_thread::sleep_for(std::chrono::milliseconds(500));


        REQUIRE(TracklistRequestReceived == true );

        if (TracklistRequestReceived == true)
        {
          SimCore::TracklistUpdate *update = new SimCore::TracklistUpdate(ID_);

        int amount = 5;
        addTracksToTracklistUpdate(update, amount);
        LOG_S(INFO)<<update->getTracks().size();
        REQUIRE(update->getTracks().size() == amount );


        server.sendMessage(update->buildMessage());
        
        
        }

        LOG_S(INFO)<<"stop";
        *running = false;
        std::this_thread::sleep_for(std::chrono::milliseconds(200));

  
          auto j =   nlohmann::json::parse(msgqueue_in_.get());
      
        REQUIRE(j["Message"] == "Hello world" );

        t1.join();
        t2.join();

      
      } //THEN
        // client->disconnect();
    } // WHEN
  } // GIVEN
} //SCENARIO