#include "SimControl/TrackItem.hpp"
#include "SimCore/SimCore.hpp"
#include "nlohmann/json_fwd.hpp"
#include <SimControl/Tracklist.hpp>
#include <ctime>
#include <string>
#include <utility>




namespace SimControl 
{
     
    TrackList::TrackList()
    {

        TrackStore_ =  std::map<std::string, std::shared_ptr<SimControl::TrackItem>>();
    }

    void TrackList::addTrack(std::shared_ptr<SimControl::TrackItem> Track)
    {

        std::lock_guard<std::mutex> lock(mx_);
        checkTracksTimeout();

        auto [iterator, inserted] = TrackStore_.try_emplace(Track->getIdentifier().getUUID(),Track);
        if (!inserted) 
        {
            if (iterator->second->isMarkedAsDelete() == false) 
            {
                iterator->second = Track; 
            } 
        }else {
            mx_.unlock();
            LOG_S(INFO)<< "Track added  new Size:" << this->getTracklistSize();
        }

    }



    void TrackList::checkTracksTimeout()
    {       

        for (std::map<std::string, std::shared_ptr<SimControl::TrackItem>>::iterator it=TrackStore_.begin(); it !=  TrackStore_.end();)
        {

            if ((time(0) - it->second->getLastUpdateTimestamp())>= TrackTimeoutTime ) 
            {
                it = TrackStore_.erase(it);
            }else {
                it++;
            }
            
        }
        
                    
        
    }


    std::shared_ptr<SimControl::TrackItem> TrackList::getTrack(const SimCore::Identifier ID)
    {
        std::lock_guard<std::mutex> lock(mx_);

        auto it =  TrackStore_.find(ID.getUUID());
        return it->second;
    }

    std::shared_ptr<SimCore::SimTrack> TrackList::getTrackBySringID(std::string ID)
    {
        std::lock_guard<std::mutex> lock(mx_);

        auto it =  TrackStore_.find(ID);
        return it->second;
    }

    void TrackList::deleteTrack(std::string ID)
    {
        std::lock_guard<std::mutex> lock(mx_);
        auto it =  TrackStore_.find(ID);
        if(it != TrackStore_.end())
        {
            it->second->markAsDelete();
            // markedAsDeletedTracks_.emplace(std::make_pair(ID, std::time(0)));
            // TrackStore_.erase(it);
        }
    }

    void TrackList::deleteTrack(SimCore::Identifier ID)
    {
        std::lock_guard<std::mutex> lock(mx_);
        // markedAsDeletedTracks_.emplace(std::make_pair(ID.getUUID(), std::time(0)));
        auto it =  TrackStore_.find(ID.getUUID());
        it->second->markAsDelete();
        // TrackStore_.erase(it);
    }


    void TrackList::getJsonTRackList(nlohmann::json &message)
    {

        std::lock_guard<std::mutex> lock(mx_);
        checkTracksTimeout();
        try {
        for (std::map<std::string, std::shared_ptr<SimControl::TrackItem>>::iterator it=TrackStore_.begin(); it!=TrackStore_.end(); ++it)
        {
            if(!it->second->isMarkedAsDelete())
            {
                message["Entities"].push_back(it->second->toJSON());
            }
            // nlohmann::json j;
            // j["id"] = it->first;
            // j["Name"] = it->second->Name.getValue();
            // j["Course"] = it->second->Course.getValue();
            // j["Speed"] = it->second->Speed.getValue();
            // j["External"] = false;
            // j["Position"] = {it->second->getPosition().getGeodesicPos()[SimCore::LATITUDE], it->second->getPosition().getGeodesicPos()[SimCore::LONGITUDE]};
            // j["Height"] = it->second->getPosition().getGeodesicPos()[SimCore::HEIGHT];
            // j["Type"] = SimCore::Kind::EntityKindMap[it->second->EntityKind.getValue()];
            // j["Side"] = SimCore::Side::EntitySideMap[it->second->EntitySide.getValue()];
            

        }
        }catch (const std::exception e) {
            LOG_S(ERROR)<< e.what();
        }
    }


    size_t TrackList::getTracklistSize()
    {
        std::lock_guard<std::mutex> lock(mx_);
        size_t size = this->TrackStore_.size();
        return size;

    }



       
}