#include <maps/wikimap/mapspro/services/mrc/toloka/tools/classification_result_handler/tool.h>
#include <maps/wikimap/mapspro/services/mrc/toloka/tools/classification_result_handler/types.h>
#include <maps/libs/geolib/include/point.h>

#define BOOST_TEST_DYN_LINK
#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp>

namespace maps {
namespace mrc {
namespace toloka {
namespace test {

namespace {

const std::string TS_1 = "task-suite-id-1";
const std::string TS_2 = "task-suite-id-2";

const std::string POOL_ID = "1";

const std::string USER_1 = "user-id-1";
const std::string USER_2 = "user-id-2";
const std::string USER_3 = "user-id-3";

const std::string SOURCE_1 = "source-1";
const std::string SOURCE_2 = "source-2";
const std::string SOURCE_3 = "source-3";
const std::string SOURCE_4 = "source-4";
const std::string SOURCE_5 = "source-5";
const std::string SOURCE_6 = "source-6";

constexpr size_t OVERLAP = 3;

const Bbox bbox = Bbox{geolib3::Point2(100, 100), geolib3::Point2(200, 200)};

const std::string SIGN_RU_2_1 = "sign_ru_2.1";
const std::string SIGN_RU_2_2 = "sign_ru_2.2";
const std::string SIGN_RU_3_1 = "sign_ru_3.1";
const std::string SIGN_RU_3_27 = "sign_ru_3.27";
const std::string SIGN_RU_4_1_1 = "sign_ru_4_1_1";
const std::string SIGN_RU_5_19_1 = "sign_ru_5_19_1";

} // anonymous namespace

BOOST_AUTO_TEST_CASE(merge_task_suites)
{
    IdToTaskSuite idToTaskSuite {
        {TS_1, {TS_1, POOL_ID, OVERLAP,
                {
                    TaskInput(SOURCE_1, bbox),
                    TaskInput(SOURCE_2, bbox),
                    TaskInput(SOURCE_3, bbox),
                    TaskInput(SOURCE_4, bbox),
                    TaskInput(SOURCE_5, bbox)
                }}
        },
        {TS_2, {TS_2, POOL_ID, OVERLAP, { TaskInput(SOURCE_6, bbox) } } }
    };

    TaskSuiteIdToResults taskSuiteIdToResults {
        /** In task suite 1:
         *  task1 - all users agree it is sign 3.1
         *  task2 - 2 users say it is sign 2.1, 1 user says it is sign 2.2
         *  task3 - 3 users give 3 different answers
         *  task4 - not classified by 2 users and not recognized by 1 user
         *  task5 - classified as sign 5.19.1 by 1 user, and not recognized by 2 others
         */
        {TS_1, {
            {
                // Result from user 1
                TS_1, "unused", io::AssignmentStatus::Submitted, USER_1,
                {
                    TaskInput(SOURCE_1, bbox),
                    TaskInput(SOURCE_2, bbox),
                    TaskInput(SOURCE_3, bbox),
                    TaskInput(SOURCE_4, bbox),
                    TaskInput(SOURCE_5, bbox)
                },
                {
                    TaskOutput(TaskAnswer::Ok, SIGN_RU_3_1),
                    TaskOutput(TaskAnswer::Ok, SIGN_RU_2_1),
                    TaskOutput(TaskAnswer::Ok, SIGN_RU_3_27),
                    TaskOutput(TaskAnswer::NotClassified, ""),
                    TaskOutput(TaskAnswer::Ok, SIGN_RU_5_19_1),
                }
            },
            {
                // Result from user 2
                TS_1, "unused", io::AssignmentStatus::Submitted, USER_2,
                {
                    TaskInput(SOURCE_1, bbox),
                    TaskInput(SOURCE_2, bbox),
                    TaskInput(SOURCE_3, bbox),
                    TaskInput(SOURCE_4, bbox),
                    TaskInput(SOURCE_5, bbox)
                },
                {
                    TaskOutput(TaskAnswer::Ok, SIGN_RU_3_1),
                    TaskOutput(TaskAnswer::Ok, SIGN_RU_2_1),
                    TaskOutput(TaskAnswer::Ok, SIGN_RU_5_19_1),
                    TaskOutput(TaskAnswer::NotClassified, ""),
                    TaskOutput(TaskAnswer::NotRecognized, "")
                }
            },
            {
                // Result from user 3
                TS_1, "unused", io::AssignmentStatus::Submitted, USER_3,
                {
                    TaskInput(SOURCE_1, bbox),
                    TaskInput(SOURCE_2, bbox),
                    TaskInput(SOURCE_3, bbox),
                    TaskInput(SOURCE_4, bbox),
                    TaskInput(SOURCE_5, bbox)
                },
                {
                    TaskOutput(TaskAnswer::Ok, SIGN_RU_3_1),
                    TaskOutput(TaskAnswer::Ok, SIGN_RU_2_2),
                    TaskOutput(TaskAnswer::Ok, SIGN_RU_4_1_1),
                    TaskOutput(TaskAnswer::NotRecognized, ""),
                    TaskOutput(TaskAnswer::NotRecognized, "")
                }
            }
        }},

        /** In task suite 2:
         *  Only 2 users accomplished the assignment, result is not ready
         */
        {TS_2, {
            {
                TS_2, "unused", io::AssignmentStatus::Submitted, USER_1,
                {
                    TaskInput(SOURCE_6, bbox)
                },
                {
                    TaskOutput(TaskAnswer::Ok, SIGN_RU_2_1)
                }
            },
            {
                TS_2, "unused", io::AssignmentStatus::Submitted, USER_2,
                {
                    TaskInput(SOURCE_6, bbox)
                },
                {
                    TaskOutput(TaskAnswer::Ok, SIGN_RU_2_1)
                }
            }
        }}
    };

    auto tsResults = mergeTasksResults(idToTaskSuite, taskSuiteIdToResults);

    // Validate classification results
    // Results are available only for task suite 1, but not for
    // task suite 2, where not enough users have accomplished the assignments
    BOOST_ASSERT_MSG(tsResults.size() == 1, "Wrong number of results");
    const auto& taskResults = tsResults[0].taskResults;

    BOOST_ASSERT_MSG(taskResults.size() == 5, "Wrong number of tasks in task suite 1");

    BOOST_CHECK_EQUAL(taskResults[0].output.answer, TaskAnswer::Ok);
    BOOST_CHECK_EQUAL(taskResults[0].output.signId, SIGN_RU_3_1);

    BOOST_CHECK_EQUAL(taskResults[1].output.answer, TaskAnswer::Ok);
    BOOST_CHECK_EQUAL(taskResults[1].output.signId, SIGN_RU_2_1);

    BOOST_CHECK_EQUAL(taskResults[2].output.answer, TaskAnswer::NotRecognized);
    BOOST_CHECK_EQUAL(taskResults[3].output.answer, TaskAnswer::NotClassified);
    BOOST_CHECK_EQUAL(taskResults[4].output.answer, TaskAnswer::NotRecognized);

    // Validate user statistics
    const auto& stat1 = tsResults[0].userIdToStat.at(USER_1);
    const auto& stat2 = tsResults[0].userIdToStat.at(USER_2);
    const auto& stat3 = tsResults[0].userIdToStat.at(USER_3);

    BOOST_CHECK_EQUAL(stat1.tasksCount, 5);
    BOOST_CHECK_EQUAL(stat1.correctCount, 4);

    BOOST_CHECK_EQUAL(stat2.tasksCount, 5);
    BOOST_CHECK_EQUAL(stat2.correctCount, 4);

    BOOST_CHECK_EQUAL(stat3.tasksCount, 5);
    BOOST_CHECK_EQUAL(stat3.correctCount, 2);
}

} // test
} // toloka
} // mrc
} // maps
