#include <maps/libs/local_postgres/include/instance.h>

#include <library/cpp/testing/gtest/gtest.h>
#include <library/cpp/testing/unittest/env.h>

#include <pqxx/except>

namespace maps::fw_updater::tests {

namespace {

const std::string MRC_MIGRATIONS_PATH
    = ArcadiaSourceRoot()
       + "/maps/wikimap/mapspro/services/mrc/drive/firmware_updater/migrations/migrations";

} // namespace

TEST(Migrations, test_firmware_rollout_triggers)
{
    local_postgres::Database postgres;
    postgres.applyMigrations(MRC_MIGRATIONS_PATH);
    postgres.executeSqlInTransaction(
        "INSERT INTO firmware.hardware(id, idm_project_id) VALUES('test_hardware', 1);"
        "INSERT INTO firmware.branch(name) VALUES('testing');"
        "INSERT INTO firmware.firmware(id, hardware_id, slot, version, version_seq, url, size, md5) VALUES"
            "(100, 'test_hardware', 'rootfs', 'v.1', 10000, 'url', 32768, 'md5'),"
            "(101, 'test_hardware', 'rootfs', 'v.2', 10001, 'url', 32768, 'md5'),"
            "(102, 'test_hardware', 'rootfs', 'v.3', 10002, 'url', 32768, 'md5');"
    );

    postgres.executeSqlInTransaction(
        "INSERT INTO firmware.rollout(id, branch, firmware_id, seed) "
            "VALUES(200, 'testing', 101, 'seed1');"
    );

    // Can't downgrade version_seq
    EXPECT_THROW(
        postgres.executeSqlInTransaction(
            "INSERT INTO firmware.rollout(id, branch, firmware_id, seed) "
            "VALUES(201, 'testing', 100, 'seed0');"),
        pqxx::plpgsql_raise
    );

    postgres.executeSqlInTransaction(
        "INSERT INTO firmware.rollout(id, branch, firmware_id, seed) "
            "VALUES(202, 'testing', 102, 'seed1');"
    );

    postgres.executeSqlInTransaction(
        "INSERT INTO firmware.rollout_history(rollout_id, percent, status, created_at, created_by) "
            "VALUES(200, 15, 'active', '2020-07-08 12:00:00', 'login');"
    );

    // Can't have more than one active experiment
    EXPECT_THROW(
        postgres.executeSqlInTransaction(
            "INSERT INTO firmware.rollout_history(rollout_id, percent, status, created_at, created_by) "
            "VALUES(202, 15, 'active', '2020-07-08 12:00:00', 'login');"),
        pqxx::plpgsql_raise
    );

    // Can't decrease experiment percent
    EXPECT_THROW(
        postgres.executeSqlInTransaction(
            "INSERT INTO firmware.rollout_history(rollout_id, percent, status, created_at, created_by) "
            "VALUES(200, 10, 'active', '2020-07-08 12:00:00', 'login');"),
        pqxx::plpgsql_raise
    );

    // Can increase experiment percent
    postgres.executeSqlInTransaction(
        "INSERT INTO firmware.rollout_history(rollout_id, percent, status, created_at, created_by) "
            "VALUES(200, 20, 'active', '2020-07-08 12:00:00', 'login');"
    );

    // Mark rollout inactive
    postgres.executeSqlInTransaction(
        "INSERT INTO firmware.rollout_history(rollout_id, percent, status, created_at, created_by) "
            "VALUES(200, 20, 'inactive', '2020-07-08 12:00:00', 'login');"
    );

    // Can switch to another experiment, since the current one is inactive
    postgres.executeSqlInTransaction(
        "INSERT INTO firmware.rollout_history(rollout_id, percent, status, created_at, created_by) "
            "VALUES(202, 10, 'active', '2020-07-08 12:00:00', 'login');"
    );

    // Try switching to an older rollout. Can't restore rollout from the past
    EXPECT_THROW(
        postgres.executeSqlInTransaction(
            "INSERT INTO firmware.rollout_history(rollout_id, percent, status, created_at, created_by) "
            "VALUES(200, 10, 'active', '2020-07-08 12:00:00', 'login');"),
        pqxx::plpgsql_raise
    );

    // Expand current experiment to 100%
    postgres.executeSqlInTransaction(
        "INSERT INTO firmware.rollout_history(rollout_id, percent, status, created_at, created_by) "
            "VALUES(202, 100, 'active', '2020-07-08 12:00:00', 'login');"
    );

}


} //namespace maps::fw_updater::tests
