#include "fixture.h"
#include "mapreduce/yt/interface/common.h"

#include <maps/wikimap/mapspro/services/mrc/long_tasks/drive_activity_stat/lib/process_yt_tables.h>
#include <maps/wikimap/mapspro/services/mrc/long_tasks/drive_activity_stat/lib/types.h>
#include <maps/wikimap/mapspro/services/mrc/long_tasks/drive_activity_stat/lib/yt_tables_types.h>

#include <maps/wikimap/mapspro/services/mrc/libs/yt/include/io.h>

#include <maps/libs/chrono/include/time_point.h>
#include <maps/libs/introspection/include/comparison.h>
#include <maps/libs/introspection/include/stream_output.h>
#include <maps/libs/log8/include/log8.h>

#include <mapreduce/yt/tests/yt_unittest_lib/yt_unittest_lib.h>
#include <mapreduce/yt/interface/client_method_options.h>

#include <library/cpp/testing/gmock_in_unittest/gmock.h>
#include <library/cpp/testing/unittest/env.h>
#include <library/cpp/testing/unittest/registar.h>


namespace maps::mrc::drive_activity_stat {

using maps::introspection::operator==;
using maps::introspection::operator<<;

std::ostream& operator<<(std::ostream& out,
    const DeviceDailyActivityRecord& record)
{
    out << "date= " << chrono::formatIsoDate(
            std::chrono::time_point_cast<chrono::TimePoint::duration>(record.date))
        << ", deviceId = " << record.deviceId;
    if (record.firmwareVersion.has_value()) {
        out << ", firmwareVersion = " << record.firmwareVersion.value();
    }
    out << ", duration = " << record.activePeriodDuration.count() << "min";
    return out;
}

std::ostream& operator<<(std::ostream& out,
    const TelematicsDailyActivityRecord& record)
{
    out << "date= " << chrono::formatIsoDate(
            std::chrono::time_point_cast<chrono::TimePoint::duration>(record.date))
        << ", telematicsImei = " << record.telematicsImei
        << ", duration = " << record.activePeriodDuration.count() << "min";
    return out;
}

} // namespace maps::mrc::drive_activity_stat

namespace maps::mrc::drive_activity_stat::tests {

namespace {

const std::string FIRMWARE_UPDATER_HOST = "firmware-updater.maps.yandex.net";
const std::string DEVICE_ID_1 = "123";
const std::string DEVICE_ID_2 = "456";
const std::string VERSION_1 = "VERSION_1";
const std::string VERSION_2 = "VERSION_2";

class YtFixture : public Fixture
{
public:

    YtFixture()
        : ytClientPtr_(NYT::NTesting::CreateTestClient())
        , rootTestDir_("//test")
    {
        ytClient().Create(rootTestDir_, NYT::NT_MAP);
    }

    ~YtFixture()
    {
        if (ytClientPtr_->Exists(rootTestDir_)) {
            ytClientPtr_->Remove(rootTestDir_,
                NYT::TRemoveOptions()
                    .Recursive(true));
        }

    }

    const TString& rootTestDir() const { return rootTestDir_; }


    NYT::IClientBase& ytClient() { return *ytClientPtr_; }

private:
    NYT::IClientPtr ytClientPtr_;
    TString rootTestDir_;
};


Date parseDate(const std::string &str)
{
    return std::chrono::time_point_cast<chrono::Days>(chrono::parseIsoDate(str));
}

std::string makeFirmwareUpdaterRequest(const std::string& deviceId)
{
    return "/firmware/1.x/target_state?hardware=mrc-signalq2&deviceid=" + deviceId;
}

NYT::TNode formatUnparsedNode(const ParsedTelematicsRecord& record)
{
    return NYT::TNode::CreateMap()
        ("type", "BLACKBOX_RECORDS")
        ("event", "incoming")
        ("imei", record.telematicsImei)
        ("data",
            NYT::TNode::CreateMap()
                ("records",
                    NYT::TNode::CreateList()
                        .Add(NYT::TNode::CreateMap()
                                ("timestamp",
                                    static_cast<int64_t>(
                                        std::chrono::duration_cast<std::chrono::seconds>(
                                            record.time.time_since_epoch()).count())
                                )
                                ("subrecords",
                                    NYT::TNode::CreateList()
                                        .Add(NYT::TNode::CreateMap()
                                                ("type", "position_data")
                                                ("lon", record.geoPos.x())
                                                ("lat", record.geoPos.y())
                                            )
                                )
                            )
                )
        );
}

template<typename Container, typename Formatter>
void saveToTable(
        NYT::IIOClient& client,
        Formatter formatter,
        const NYT::TRichYPath& path,
        const Container& container)
{
    const auto writer = client.CreateTableWriter<NYT::TNode>(path);

    std::for_each(
        container.begin(), container.end(),
        [&writer, formatter](const auto& entity) {
            writer->AddRow(formatter(entity));
        }
    );
}


} // namespace

Y_UNIT_TEST_SUITE_F(process_yt_tables_should, YtFixture)
{

Y_UNIT_TEST(eval_tables_to_process)
{
    ytClient().Create(rootTestDir() + "/2021-01-03", NYT::NT_MAP);
    ytClient().Create(rootTestDir() + "/2021-11-01", NYT::NT_MAP);
    ytClient().Create(rootTestDir() + "/2021-11-03", NYT::NT_MAP);
    ytClient().Create(rootTestDir() + "/2020-11-03", NYT::NT_MAP);

    EXPECT_THAT(evalTablesToProcess(ytClient(), rootTestDir(), {}),
        ::testing::ElementsAre("2020-11-03", "2021-01-03", "2021-11-01", "2021-11-03"));

    EXPECT_THAT(evalTablesToProcess(ytClient(), rootTestDir(), "2020-11-03"),
        ::testing::ElementsAre("2021-01-03", "2021-11-01", "2021-11-03"));

    EXPECT_THAT(evalTablesToProcess(ytClient(), rootTestDir(), "2021-01-03"),
        ::testing::ElementsAre("2021-11-01", "2021-11-03"));

    EXPECT_THAT(evalTablesToProcess(ytClient(), rootTestDir(), "2021-11-03"),
        ::testing::ElementsAre());
}

Y_UNIT_TEST(camera_activity_correctly_parse_logs_table)
{
    const std::string LOGS_TABLE = rootTestDir() + "/2021-11-01";
    const std::string OUTPUT_TABLE = rootTestDir() + "/output";

    auto writer = ytClient().CreateTableWriter<NYT::TNode>(
        NYT::TRichYPath(TString(LOGS_TABLE)).SortedBy({"vhost"}));

    writer->AddRow(NYT::TNode::CreateMap()
        ("vhost",TString(FIRMWARE_UPDATER_HOST))
        ("iso_eventtime", "2021-11-01 05:05:31")
        ("request",
            "/firmware/1.x/target_state?hardware=mrc-signalq2&deviceid=22202279036D1&slots=rootfs")
        ("user_agent", TString(VERSION_1)));

    writer->AddRow(NYT::TNode::CreateMap()
        ("vhost",TString(FIRMWARE_UPDATER_HOST))
        ("iso_eventtime", "2021-11-01 05:15:31")
        ("request",
            "/firmware/1.x/target_state?hardware=mrc-signalq2&deviceid=22202279036D1&slots=rootfs")
        ("user_agent", TString(VERSION_1)));

    writer->AddRow(NYT::TNode::CreateMap()
        ("vhost", "yetanotherhost")
        ("iso_eventtime", "2021-11-01 06:05:31")
        ("request",
            "/firmware/1.x/target_state?hardware=mrc-signalq2&deviceid=22202279036D1&slots=rootfs")
        ("user_agent", "-")("extra_field", "value"));
    writer->Finish();

    calculateCameraActivity(ytClient(), FIRMWARE_UPDATER_HOST,
        rootTestDir(), {"2021-11-01"}, OUTPUT_TABLE, std::nullopt);

    auto activityRecords =
        yt::loadFromTable<std::vector<DeviceDailyActivityRecord>>(
            ytClient(), TString(OUTPUT_TABLE));

    std::vector<DeviceDailyActivityRecord> expectedRecords{
        DeviceDailyActivityRecord{
            .date = parseDate("2021-11-01"),
            .deviceId = "22202279036D1",
            .firmwareVersion = VERSION_1,
            .activePeriodDuration = std::chrono::minutes(10)}
    };

    EXPECT_THAT(activityRecords, ::testing::ContainerEq(expectedRecords));
}

Y_UNIT_TEST(camera_activity_correctly_process_inactivity_periods)
{
    const std::string LOGS_TABLE = rootTestDir() + "/2021-11-01";
    const std::string OUTPUT_TABLE = rootTestDir() + "/output";

    auto makeLogRecord = [&](const std::string& isoEventTime)
        {
            return ServiceLogRecord{
                .vhost = FIRMWARE_UPDATER_HOST,
                .isoEventtime = isoEventTime,
                .request = makeFirmwareUpdaterRequest(DEVICE_ID_1),
                .userAgent = VERSION_1
            };
        };

    yt::saveToTable(ytClient(), TString(LOGS_TABLE),
        std::vector<ServiceLogRecord>{
            makeLogRecord("2021-11-01 05:15:30"),
            makeLogRecord("2021-11-01 05:15:31"),
            makeLogRecord("2021-11-01 05:15:35"),
            makeLogRecord("2021-11-01 05:45:34"), // less than threshold
            makeLogRecord("2021-11-01 06:15:35"), // more than threshold
            makeLogRecord("2021-11-01 06:25:35"),
        });
    sortTable(ytClient(), LOGS_TABLE, {"vhost"});

    calculateCameraActivity(ytClient(), FIRMWARE_UPDATER_HOST,
        rootTestDir(), {"2021-11-01"}, OUTPUT_TABLE, std::nullopt);

    auto activityRecords =
        yt::loadFromTable<std::vector<DeviceDailyActivityRecord>>(
            ytClient(), TString(OUTPUT_TABLE));

    std::vector<DeviceDailyActivityRecord> expectedRecords{
        DeviceDailyActivityRecord{
            .date = parseDate("2021-11-01"),
            .deviceId = DEVICE_ID_1,
            .firmwareVersion = VERSION_1,
            .activePeriodDuration = std::chrono::minutes(40)}
    };

    EXPECT_THAT(activityRecords, ::testing::ContainerEq(expectedRecords));
}

Y_UNIT_TEST(camera_activity_consider_device_id)
{
    const std::string LOGS_TABLE = rootTestDir() + "/2021-11-01";
    const std::string OUTPUT_TABLE = rootTestDir() + "/output";

    auto makeLogRecord = [&](const std::string& isoEventTime, const std::string& deviceId)
        {
            return ServiceLogRecord{
                .vhost = FIRMWARE_UPDATER_HOST,
                .isoEventtime = isoEventTime,
                .request = makeFirmwareUpdaterRequest(deviceId),
                .userAgent = VERSION_1
            };
        };

    yt::saveToTable(ytClient(), TString(LOGS_TABLE),
        std::vector<ServiceLogRecord>{
            makeLogRecord("2021-11-01 05:15:30", DEVICE_ID_1),
            makeLogRecord("2021-11-01 05:25:30", DEVICE_ID_2),
            makeLogRecord("2021-11-01 05:35:30", DEVICE_ID_1),
            makeLogRecord("2021-11-01 05:50:30", DEVICE_ID_2),
            makeLogRecord("2021-11-01 06:05:31", DEVICE_ID_1), // more than threshold
            makeLogRecord("2021-11-01 06:20:31", DEVICE_ID_2), // more than threshold
        });
    sortTable(ytClient(), LOGS_TABLE, {"vhost"});

    calculateCameraActivity(ytClient(), FIRMWARE_UPDATER_HOST,
        rootTestDir(), {"2021-11-01"}, OUTPUT_TABLE, std::nullopt);

    auto activityRecords =
        yt::loadFromTable<std::vector<DeviceDailyActivityRecord>>(
            ytClient(), TString(OUTPUT_TABLE));

    std::vector<DeviceDailyActivityRecord> expectedRecords{
        DeviceDailyActivityRecord{
            .date = parseDate("2021-11-01"),
            .deviceId = DEVICE_ID_1,
            .firmwareVersion = VERSION_1,
            .activePeriodDuration = std::chrono::minutes(20)},
        DeviceDailyActivityRecord{
            .date = parseDate("2021-11-01"),
            .deviceId = DEVICE_ID_2,
            .firmwareVersion = VERSION_1,
            .activePeriodDuration = std::chrono::minutes(25)}
    };

    EXPECT_THAT(activityRecords, ::testing::ContainerEq(expectedRecords));
}

Y_UNIT_TEST(camera_activity_consider_version)
{
    const std::string LOGS_TABLE = rootTestDir() + "/2021-11-01";
    const std::string OUTPUT_TABLE = rootTestDir() + "/output";

    auto makeLogRecord = [&](const std::string& isoEventTime, const std::string& version)
        {
            return ServiceLogRecord{
                .vhost = FIRMWARE_UPDATER_HOST,
                .isoEventtime = isoEventTime,
                .request = makeFirmwareUpdaterRequest(DEVICE_ID_1),
                .userAgent = version
            };
        };

    yt::saveToTable(ytClient(), TString(LOGS_TABLE),
        std::vector<ServiceLogRecord>{
            makeLogRecord("2021-11-01 05:15:30", VERSION_1),
            makeLogRecord("2021-11-01 05:25:30", VERSION_2),
            makeLogRecord("2021-11-01 05:35:30", VERSION_1),
            makeLogRecord("2021-11-01 05:50:30", VERSION_2),
            makeLogRecord("2021-11-01 06:05:31", VERSION_1), // more than threshold
            makeLogRecord("2021-11-01 06:20:31", VERSION_2), // more than threshold
        });
    sortTable(ytClient(), LOGS_TABLE, {"vhost"});

    calculateCameraActivity(ytClient(), FIRMWARE_UPDATER_HOST,
        rootTestDir(), {"2021-11-01"}, OUTPUT_TABLE, std::nullopt);

    auto activityRecords =
        yt::loadFromTable<std::vector<DeviceDailyActivityRecord>>(
            ytClient(), TString(OUTPUT_TABLE));

    std::vector<DeviceDailyActivityRecord> expectedRecords{
        DeviceDailyActivityRecord{
            .date = parseDate("2021-11-01"),
            .deviceId = DEVICE_ID_1,
            .firmwareVersion = VERSION_1,
            .activePeriodDuration = std::chrono::minutes(20)},
        DeviceDailyActivityRecord{
            .date = parseDate("2021-11-01"),
            .deviceId = DEVICE_ID_1,
            .firmwareVersion = VERSION_2,
            .activePeriodDuration = std::chrono::minutes(25)}
    };

    EXPECT_THAT(activityRecords, ::testing::ContainerEq(expectedRecords));
}

Y_UNIT_TEST(camera_activity_correctly_process_day_change)
{
    const std::string LOGS_TABLE_1 = rootTestDir() + "/2021-11-01";
    const std::string LOGS_TABLE_2 = rootTestDir() + "/2021-11-02";
    const std::string OUTPUT_TABLE = rootTestDir() + "/output";

    auto makeLogRecord = [&](const std::string& isoEventTime, const std::string& deviceId)
        {
            return ServiceLogRecord{
                .vhost = FIRMWARE_UPDATER_HOST,
                .isoEventtime = isoEventTime,
                .request = makeFirmwareUpdaterRequest(deviceId),
                .userAgent = VERSION_1
            };
        };

    yt::saveToTable(ytClient(), TString(LOGS_TABLE_1),
        std::vector<ServiceLogRecord>{
            makeLogRecord("2021-11-01 23:35:00", DEVICE_ID_1),
            makeLogRecord("2021-11-01 23:35:00", DEVICE_ID_2),
            makeLogRecord("2021-11-01 23:45:00", DEVICE_ID_1),
            makeLogRecord("2021-11-01 23:45:00", DEVICE_ID_2),
        });
    sortTable(ytClient(), LOGS_TABLE_1, {"vhost"});

    yt::saveToTable(ytClient(), TString(LOGS_TABLE_2),
        std::vector<ServiceLogRecord>{
            makeLogRecord("2021-11-02 00:14:59", DEVICE_ID_1),
            makeLogRecord("2021-11-02 00:16:00", DEVICE_ID_2), // more that threshold
            makeLogRecord("2021-11-02 00:20:00", DEVICE_ID_1),
            makeLogRecord("2021-11-02 00:21:00", DEVICE_ID_2),
        });
    sortTable(ytClient(), LOGS_TABLE_2, {"vhost"});

    calculateCameraActivity(ytClient(), FIRMWARE_UPDATER_HOST,
        rootTestDir(), {"2021-11-01", "2021-11-02"}, OUTPUT_TABLE, std::nullopt);

    auto activityRecords =
        yt::loadFromTable<std::vector<DeviceDailyActivityRecord>>(
            ytClient(), TString(OUTPUT_TABLE));

    std::vector<DeviceDailyActivityRecord> expectedRecords{
        DeviceDailyActivityRecord{
            .date = parseDate("2021-11-01"),
            .deviceId = DEVICE_ID_1,
            .firmwareVersion = VERSION_1,
            .activePeriodDuration = std::chrono::minutes(25)},
        DeviceDailyActivityRecord{
            .date = parseDate("2021-11-01"),
            .deviceId = DEVICE_ID_2,
            .firmwareVersion = VERSION_1,
            .activePeriodDuration = std::chrono::minutes(10)},
        DeviceDailyActivityRecord{
            .date = parseDate("2021-11-02"),
            .deviceId = DEVICE_ID_1,
            .firmwareVersion = VERSION_1,
            .activePeriodDuration = std::chrono::minutes(20)},
        DeviceDailyActivityRecord{
            .date = parseDate("2021-11-02"),
            .deviceId = DEVICE_ID_2,
            .firmwareVersion = VERSION_1,
            .activePeriodDuration = std::chrono::minutes(5)}
    };

    EXPECT_THAT(activityRecords, ::testing::ContainerEq(expectedRecords));
}


Y_UNIT_TEST(camera_activity_merge_with_empty_table)
{
    const std::string TABLE_1 = rootTestDir() + "/2021-11-01";
    const std::string TABLE_2 = rootTestDir() + "/2021-11-02";
    const std::string TABLE_3 = rootTestDir() + "/2021-11-03";

    std::vector<DeviceDailyActivityRecord> records{
            DeviceDailyActivityRecord{
            .date = parseDate("2021-11-01"),
            .deviceId = DEVICE_ID_1,
            .firmwareVersion = VERSION_1,
            .activePeriodDuration = std::chrono::minutes(25)},
        DeviceDailyActivityRecord{
            .date = parseDate("2021-11-02"),
            .deviceId = DEVICE_ID_1,
            .firmwareVersion = VERSION_1,
            .activePeriodDuration = std::chrono::minutes(20)}
        };

    yt::saveToTable(ytClient(), TString(TABLE_1), records);
    yt::saveToTable(ytClient(), TString(TABLE_2),
        std::vector<DeviceDailyActivityRecord>{});
    yt::saveToTable(ytClient(), TString(TABLE_3),
        std::vector<DeviceDailyActivityRecord>{});

    sortTable(ytClient(), TABLE_1, {"date"});
    sortTable(ytClient(), TABLE_2, {"date"});
    sortTable(ytClient(), TABLE_3, {"date"});

    mergeCameraActivityTables(ytClient(), TABLE_1, TABLE_2, std::nullopt);
    sortTable(ytClient(), TABLE_2, {"date"});
    mergeCameraActivityTables(ytClient(), TABLE_3, TABLE_2, std::nullopt);

    auto activityRecords1 =
        yt::loadFromTable<std::vector<DeviceDailyActivityRecord>>(
            ytClient(), TString(TABLE_1));

    auto activityRecords2 =
        yt::loadFromTable<std::vector<DeviceDailyActivityRecord>>(
            ytClient(), TString(TABLE_2));

    auto activityRecords3 =
        yt::loadFromTable<std::vector<DeviceDailyActivityRecord>>(
            ytClient(), TString(TABLE_3));

    EXPECT_THAT(activityRecords1, ::testing::ContainerEq(records));
    EXPECT_THAT(activityRecords2, ::testing::ContainerEq(records));
    EXPECT_TRUE(activityRecords3.empty());
}

Y_UNIT_TEST(camera_activity_merge_correctly_overrites_records)
{
    const std::string TABLE_1 = rootTestDir() + "/2021-11-01";
    const std::string TABLE_2 = rootTestDir() + "/2021-11-02";

    yt::saveToTable(
        ytClient(),
        TString(TABLE_1),
        std::vector<DeviceDailyActivityRecord>{
            DeviceDailyActivityRecord{
                .date = parseDate("2021-11-01"),
                .deviceId = DEVICE_ID_1,
                .firmwareVersion = VERSION_1,
                .activePeriodDuration = std::chrono::minutes(25)},
            DeviceDailyActivityRecord{
                .date = parseDate("2021-11-02"),
                .deviceId = DEVICE_ID_1,
                .firmwareVersion = VERSION_1,
                .activePeriodDuration = std::chrono::minutes(20)}});
    yt::saveToTable(
        ytClient(),
        TString(TABLE_2),
        std::vector<DeviceDailyActivityRecord>{
            DeviceDailyActivityRecord{
                .date = parseDate("2021-11-02"),
                .deviceId = DEVICE_ID_1,
                .firmwareVersion = VERSION_1,
                .activePeriodDuration = std::chrono::minutes(25)},
            DeviceDailyActivityRecord{
                .date = parseDate("2021-11-02"),
                .deviceId = DEVICE_ID_2,
                .firmwareVersion = VERSION_1,
                .activePeriodDuration = std::chrono::minutes(25)},
            DeviceDailyActivityRecord{
                .date = parseDate("2021-11-03"),
                .deviceId = DEVICE_ID_1,
                .firmwareVersion = VERSION_1,
                .activePeriodDuration = std::chrono::minutes(10)}});

    sortTable(ytClient(), TABLE_1, {"date"});
    sortTable(ytClient(), TABLE_2, {"date"});

    mergeCameraActivityTables(ytClient(), TABLE_1, TABLE_2, std::nullopt);

    auto activityRecords =
        yt::loadFromTable<std::vector<DeviceDailyActivityRecord>>(
            ytClient(), TString(TABLE_2));

    EXPECT_THAT(activityRecords,
        ::testing::ContainerEq(
            std::vector<DeviceDailyActivityRecord>{
            DeviceDailyActivityRecord{
                .date = parseDate("2021-11-01"),
                .deviceId = DEVICE_ID_1,
                .firmwareVersion = VERSION_1,
                .activePeriodDuration = std::chrono::minutes(25)},
            DeviceDailyActivityRecord{
                .date = parseDate("2021-11-02"),
                .deviceId = DEVICE_ID_1,
                .firmwareVersion = VERSION_1,
                .activePeriodDuration = std::chrono::minutes(20)},
            DeviceDailyActivityRecord{
                .date = parseDate("2021-11-03"),
                .deviceId = DEVICE_ID_1,
                .firmwareVersion = VERSION_1,
                .activePeriodDuration = std::chrono::minutes(10)}
        }));
}

Y_UNIT_TEST(carsharing_activity_detects_movement)
{
    const std::string INPUT_TABLE_NAME = "2021-12-01";
    const std::string INPUT_TABLE = rootTestDir() + "/" + INPUT_TABLE_NAME;
    const std::string OUTPUT_TABLE = rootTestDir() + "/output";
    const int64_t imei1 = 1;
    const int64_t imei2 = 2;
    const int64_t imei3 = 3;

    saveToTable(
        ytClient(),
        formatUnparsedNode,
        TString(INPUT_TABLE),
        std::vector<ParsedTelematicsRecord>{
            ParsedTelematicsRecord{
                .telematicsImei = imei1,
                .time = chrono::parseSqlDateTime("2021-12-01 12:00:00"),
                .geoPos = geolib3::Point2(37.564832, 55.706449)
            },
            ParsedTelematicsRecord{
                .telematicsImei = imei1,
                .time = chrono::parseSqlDateTime("2021-12-01 12:01:10"),
                .geoPos = geolib3::Point2(37.562863, 55.706183)
            },
            ParsedTelematicsRecord{
                .telematicsImei = imei2,
                .time = chrono::parseSqlDateTime("2021-12-01 12:00:00"),
                .geoPos = geolib3::Point2(37.564832, 55.706449)
            },
            ParsedTelematicsRecord{
                .telematicsImei = imei2,
                .time = chrono::parseSqlDateTime("2021-12-01 12:01:10"),
                .geoPos = geolib3::Point2(37.562863, 55.706183)
            },
            ParsedTelematicsRecord{
                .telematicsImei = imei3,
                .time = chrono::parseSqlDateTime("2021-12-01 12:00:00"),
                .geoPos = geolib3::Point2(37.564832, 55.706449)
            },
            ParsedTelematicsRecord{
                .telematicsImei = imei3,
                .time = chrono::parseSqlDateTime("2021-12-01 12:01:10"),
                .geoPos = geolib3::Point2(37.562863, 55.706183)
            },
        });

    calculateCarsharingTelematicsActivity(ytClient(),
        std::vector<DevicesRegistryRecord>{
            DevicesRegistryRecord{.telematicsImei = imei1},
            DevicesRegistryRecord{.telematicsImei = imei3}
        },
        rootTestDir(), {INPUT_TABLE_NAME}, OUTPUT_TABLE, std::nullopt);

    auto activityRecords =
        yt::loadFromTable<std::vector<TelematicsDailyActivityRecord>>(
            ytClient(), TString(OUTPUT_TABLE));

    /// Records of imei2 are ignored because they were not in the registry
    EXPECT_THAT(activityRecords,
        ::testing::UnorderedElementsAre(
            TelematicsDailyActivityRecord{
                .date = parseDate(INPUT_TABLE_NAME),
                .telematicsImei = imei1,
                .activePeriodDuration = std::chrono::minutes(1)},
            TelematicsDailyActivityRecord{
                .date = parseDate(INPUT_TABLE_NAME),
                .telematicsImei = imei3,
                .activePeriodDuration = std::chrono::minutes(1)}));
}


Y_UNIT_TEST(carsharing_activity_ignores_inactivity_periods)
{
    const std::string INPUT_TABLE_NAME = "2021-12-01";
    const std::string INPUT_TABLE = rootTestDir() + "/" + INPUT_TABLE_NAME;
    const std::string OUTPUT_TABLE = rootTestDir() + "/output";
    const int64_t imei = 1;

    /// Interval 12:01:10 - 13:00:00 won't be included in total activity
    saveToTable(
        ytClient(),
        formatUnparsedNode,
        TString(INPUT_TABLE),
        std::vector<ParsedTelematicsRecord>{
                ParsedTelematicsRecord{
                    .telematicsImei = imei,
                    .time = chrono::parseSqlDateTime("2021-12-01 12:00:00"),
                    .geoPos = geolib3::Point2(37.564832, 55.706449)
                },
                ParsedTelematicsRecord{
                    .telematicsImei = imei,
                    .time = chrono::parseSqlDateTime("2021-12-01 12:01:10"),
                    .geoPos = geolib3::Point2(37.562863, 55.706183)
                },
                ParsedTelematicsRecord{
                    .telematicsImei = imei,
                    .time = chrono::parseSqlDateTime("2021-12-01 13:00:00"),
                    .geoPos = geolib3::Point2(37.562863, 55.706183)
                },
                ParsedTelematicsRecord{
                    .telematicsImei = imei,
                    .time = chrono::parseSqlDateTime("2021-12-01 13:01:00"),
                    .geoPos = geolib3::Point2(37.562893, 55.706283)
                },
            }
        );

    calculateCarsharingTelematicsActivity(ytClient(),
        std::vector<DevicesRegistryRecord>{
            DevicesRegistryRecord{.telematicsImei = imei}
        },
        rootTestDir(), {INPUT_TABLE_NAME}, OUTPUT_TABLE, std::nullopt);

    auto activityRecords =
        yt::loadFromTable<std::vector<TelematicsDailyActivityRecord>>(
            ytClient(), TString(OUTPUT_TABLE));

    EXPECT_THAT(activityRecords,
        ::testing::ElementsAre(TelematicsDailyActivityRecord{
            .date = parseDate(INPUT_TABLE_NAME),
            .telematicsImei = imei,
            .activePeriodDuration = std::chrono::minutes(2)}));
}


} // Y_UNIT_TEST_SUITE_F(process_yt_tables_should, Fixture)


} // maps::mrc::drive_activity_stat::tests

