#include <library/cpp/testing/gtest/gtest.h>
#include <maps/libs/chrono/include/time_point.h>
#include <maps/libs/geolib/include/point.h>
#include <yandex/maps/geolib3/sproto.h>
#include <maps/libs/geolib/include/test_tools/comparison.h>
#include <yandex/maps/mrc/signal_queue/result_queue.h>
#include <yandex/maps/mrc/signal_queue/results.h>

#include <boost/filesystem.hpp>

#include <chrono>
#include <sys/stat.h>
#include <sys/types.h>

namespace maps {
namespace mrc {
namespace signal_queue {
namespace tests {

namespace {

const std::string PATH = "signals";

struct SignalsDirectoryFixture : testing::Test {
    explicit SignalsDirectoryFixture()
    {
        boost::filesystem::remove_all(PATH);
        ::mkdir(PATH.c_str(), 0755);
    }

    ~SignalsDirectoryFixture()
    {
        boost::filesystem::remove_all(PATH);
    }

    const std::string& path() const
    {
        return PATH;
    }
};

} // anonymous namespace

TEST_F(SignalsDirectoryFixture, test_storing_images)
{
    using Clock = std::chrono::system_clock;

    const time_t TAKEN_AT = Clock::to_time_t(Clock::now());
    const std::string JPEG_DATA = "JPEG_DATA";
    const std::string MDS_GROUP_ID = "12345";
    const std::string MDS_PATH = "123/456.jpg";
    const uint64_t ASSIGNMENT_ID = 31337;

    sresults::Image image;
    image.created() = TAKEN_AT;
    image.image() = JPEG_DATA;
    AssignmentImage assignmentImage;
    assignmentImage.data() = std::move(image);
    assignmentImage.assignmentId() = ASSIGNMENT_ID;
    assignmentImage.mdsGroupId() = MDS_GROUP_ID;
    assignmentImage.mdsPath() = MDS_PATH;

    ResultsQueue queue(path());
    queue.push(assignmentImage);
    EXPECT_EQ(queue.count<AssignmentImage>(), 1u);

    auto popped = queue.pop<AssignmentImage>();
    EXPECT_TRUE(popped);
    EXPECT_EQ(queue.count<AssignmentImage>(), 0u);

    EXPECT_EQ(popped->assignmentId(), ASSIGNMENT_ID);
    EXPECT_TRUE(popped->mdsGroupId());
    EXPECT_EQ(popped->mdsGroupId().get(), MDS_GROUP_ID);
    EXPECT_TRUE(popped->mdsPath());
    EXPECT_EQ(popped->mdsPath().get(), MDS_PATH);
    EXPECT_EQ(popped->data().image(), JPEG_DATA);
    /*
     * WARN: no TAKEN_AT test due to hardly implementable comparison between
     * signed time_t and unsigned sproto::Uint64
     */

    EXPECT_FALSE(queue.pop<AssignmentImage>());
}

TEST_F(SignalsDirectoryFixture, test_ride_images)
{
    using Clock = std::chrono::system_clock;

    const time_t TAKEN_AT = Clock::to_time_t(Clock::now());
    const std::string JPEG_DATA = "JPEG_DATA";
    const std::string SOURCE_ID = "Samsung100500";
    const std::string USER_ID = "NotPetya";
    const std::string MDS_GROUP_ID = "12345";
    const std::string MDS_PATH = "123/456.jpg";
    const std::string CLIENT_RIDE_ID = "b0c2d8c8-6fc6-45d0-9e8e-45e37bd29636";

    sresults::Image image;
    image.created() = TAKEN_AT;
    image.image() = JPEG_DATA;
    RideImage rideImage;
    rideImage.data() = std::move(image);
    rideImage.sourceId() = SOURCE_ID;
    rideImage.userId() = USER_ID;
    rideImage.mdsGroupId() = MDS_GROUP_ID;
    rideImage.mdsPath() = MDS_PATH;
    rideImage.clientRideId() = CLIENT_RIDE_ID;

    ResultsQueue queue(path());
    queue.push(rideImage);
    EXPECT_EQ(queue.count<RideImage>(), 1u);

    auto popped = queue.pop<RideImage>();
    EXPECT_TRUE(popped);
    EXPECT_EQ(queue.count<RideImage>(), 0u);

    EXPECT_TRUE(popped->mdsGroupId());
    EXPECT_EQ(popped->mdsGroupId().get(), MDS_GROUP_ID);
    EXPECT_TRUE(popped->mdsPath());
    EXPECT_EQ(popped->mdsPath().get(), MDS_PATH);
    EXPECT_EQ(popped->data().image(), JPEG_DATA);
    EXPECT_EQ(popped->sourceId(), SOURCE_ID);
    EXPECT_EQ(popped->userId(), USER_ID);
    EXPECT_TRUE(popped->clientRideId());
    EXPECT_EQ(popped->clientRideId().get(), CLIENT_RIDE_ID);
    /*
     * WARN: no TAKEN_AT test due to hardly implementable comparison between
     * signed time_t and unsigned sproto::Uint64
     */

    EXPECT_FALSE(queue.pop<RideImage>());
}

} //namespace tests
} //namespace signal_queue
} //namespace mrc
} //namespace maps
