#include <maps/wikimap/mapspro/services/editor/src/configs/config.h>
#include <maps/wikimap/mapspro/services/editor/src/serialize/save_object_parser.h>
#include <maps/wikimap/mapspro/services/editor/src/utils.h>

#include <maps/wikimap/mapspro/services/editor/src/tests/helpers/controller_helpers.h>
#include <maps/wikimap/mapspro/services/editor/src/tests/helpers/helpers.h>
#include <maps/wikimap/mapspro/services/editor/src/tests/helpers/tests_common.h>

namespace maps::wiki::tests {

Y_UNIT_TEST_SUITE(parser)
{
WIKI_FIXTURE_TEST_CASE(test_json_parser, EditorTestFixture)
{
    log8::setLevel(log8::Level::FATAL);
    {
        auto parser = SaveObjectParser();
        UNIT_ASSERT_NO_EXCEPTION(parser.parse(common::FormatType::JSON, loadFile("tests/data/parser1.json")));
        UNIT_ASSERT(parser.objects().size() == 4);
        const UniqueId primaryObjectId(1);
        const auto& object = parser.objects()[primaryObjectId];
        UNIT_ASSERT(object.id() == primaryObjectId);
        UNIT_ASSERT(object.revision() == boost::lexical_cast<TRevisionId>("1:2"));
        UNIT_ASSERT(object.categoryId() == "rd");
        const auto& attrs = object.attributes();
        UNIT_ASSERT(attrs.size() == 2);
        UNIT_ASSERT("4" == object.attrValue("rd:rd_type"));
        UNIT_ASSERT(object.attrValue("rd:search_class") == "10");
        UNIT_ASSERT(!object.tableAttributes().empty());
        UNIT_ASSERT(*object.tableAttributes().attrNames().begin() == "rd_nm");
        const auto& tableValues = object.tableAttributes().find("rd_nm");
        UNIT_ASSERT(tableValues.numRows() == 3);
        UNIT_ASSERT(object.mastersDiff().empty());
        UNIT_ASSERT(!object.slavesDiff().empty());
        UNIT_ASSERT(object.slavesDiff().at("part").added().size() == 2);
        UNIT_ASSERT(object.slavesDiff().at("part").removed().size() == 1);
        UNIT_ASSERT(!object.geometry().isNull());
        UNIT_ASSERT(object.geometry()->getGeometryTypeId()
            == geos::geom::GEOS_LINESTRING);
    }
    {
        auto parser = SaveObjectParser();
        UNIT_ASSERT_NO_EXCEPTION(
            parser.parse(common::FormatType::JSON, loadFile("tests/data/create_ad_cnt_fc_el_el.json")));
        UNIT_ASSERT_EQUAL(parser.objects().size(), 5); // ad, ad_fc, ad_cnt, ad_el, ad_el
    }
    {
        auto parser = SaveObjectParser();
        UNIT_ASSERT_NO_EXCEPTION(
            parser.parse(common::FormatType::JSON, loadFile("tests/data/create_simple_vegetation.json")));
        UNIT_ASSERT_EQUAL(parser.objects().size(), 3); // veg, veg_fc, veg_el
    }
    {
        auto parser = SaveObjectParser();
        UNIT_ASSERT_NO_EXCEPTION(
            parser.parse(common::FormatType::JSON, loadFile("tests/data/create_ad_fc_el_el.json")));
        UNIT_ASSERT_EQUAL(parser.objects().size(), 3); // ad_fc, ad_el, ad_el
    }
    {
        auto parser = SaveObjectParser();
        UNIT_ASSERT_NO_EXCEPTION(
            parser.parse(common::FormatType::JSON, loadFile("tests/data/create_ad_cnt_fc_el_el.json")));
        UNIT_ASSERT_EQUAL(parser.objects().size(), 5); // ad, ad_fc, ad_cnt, ad_el, ad_el
    }
    {
        auto parser = SaveObjectParser();
        UNIT_ASSERT_NO_EXCEPTION(
            parser.parse(common::FormatType::JSON, loadFile("tests/data/transport_thread_linked_list.json")));
        UNIT_ASSERT_EQUAL(std::count_if(parser.objects().begin(), parser.objects().end(),
            [](const ObjectUpdateData& o) { return o.categoryId() == "transport_thread_stop";}), 3);
        size_t totalAddedStationMasters {0};
        size_t totalAddedStationSlaves {0};
        for (const auto& o : parser.objects()) {
            if (o.categoryId() != "transport_thread_stop") {
                continue;
            }
            for (const auto& rolePair : o.mastersDiff()) {
                totalAddedStationMasters += rolePair.second.added().size();
            }
            for (const auto& rolePair : o.slavesDiff()) {
                totalAddedStationSlaves += rolePair.second.added().size();
            }
        }
        UNIT_ASSERT_EQUAL(totalAddedStationMasters, 3);
        UNIT_ASSERT_EQUAL(totalAddedStationSlaves, 2);
    }
}
}// Y_UNIT_TEST_SUITE

} // namespace maps::wiki::tests
