#include "names_stat.h"

#include "config.h"
#include "names.h"
#include "nmaps_export_result.h"
#include "stat.h"

#include <maps/libs/chrono/include/time_point.h>
#include <maps/libs/json/include/builder.h>
#include <maps/libs/json/include/value.h>
#include <string>

namespace maps::wiki::merge_poi {

namespace {
namespace col {
const auto FIELDDATE = "fielddate"s;
const auto TOTAL_EQUAL = "total_equal"s;
const auto TOTAL_DIFFERENCES =  "total_differences"s;
const auto WITH_RUBRIC_NAMES = "with_rubric_names"s;
const auto WITH_SOME_SHORT_IN_FULL = "with_some_short_in_full"s;
const auto ALTAY_LANGS_LESS = "altay_langs_less"s;
const auto ALTAY_LANGS_GREATER = "altay_langs_greater"s;
const auto SAME_COUNT_LANGS_AND_NAMES = "same_count_langs_and_names"s;
const auto ONE_NAME_EACH_SET = "one_name_each_set"s;
} // namespace col

const auto NAMES_DIFF_REPORT_NAME = "Maps.Wiki/Sprav/Merge.Poi.Worker.Names.Diff"s;
const auto VALUES = "values"s;

} // namespace

std::string
NamesStat::toReportJson() const
{
    const auto fieldDate = maps::chrono::formatIsoDate(maps::chrono::TimePoint::clock::now());
    json::Builder reportBuilder;
    reportBuilder << [&](maps::json::ObjectBuilder report) {
        report[VALUES] << [&](maps::json::ArrayBuilder values) {
            values << [&](maps::json::ObjectBuilder data) {
                data[col::FIELDDATE] = fieldDate;
                data[col::TOTAL_EQUAL] = totalEqual;
                data[col::TOTAL_DIFFERENCES] = totalDifferences;
                data[col::WITH_RUBRIC_NAMES] = withRubricNames;
                data[col::WITH_SOME_SHORT_IN_FULL] = withSomeShortInFull;
                data[col::ALTAY_LANGS_LESS] = altayLangsLess;
                data[col::ALTAY_LANGS_GREATER] = altayLangsGreater;
                data[col::SAME_COUNT_LANGS_AND_NAMES] = sameCountLangsAndNames;
                data[col::ONE_NAME_EACH_SET] = oneNameEachSet;
            };
        };
    };
    return reportBuilder.str();
}

bool
NamesStat::post(const Config& cfg) const
{
    return postStat(cfg, NAMES_DIFF_REPORT_NAME, toReportJson());
}


NamesStat buildNamesStat(
    const poi_feed::FeedObjectDataVector& patches,
    const NmapsExportResult& nmapsData,
    const EditorCfg& editorCfg)
{
    NamesStat namesStat;
    for (const auto& patch : patches) {
        const auto nmapsObject = nmapsData.objectData(patch.nmapsId());
        if (!nmapsObject) {
            continue;
        }
        if (nmapsObject->names() != patch.names() ||
            nmapsObject->shortNames() != patch.shortNames()) {
                ++namesStat.totalDifferences;
        } else {
            ++namesStat.totalEqual;
            continue;
        }
        const auto& altayShort = patch.shortNames();
        const auto& altayFull = patch.names();
        if (
            std::any_of(altayFull.begin(), altayFull.end(),
                [&](const auto& name) {
                    return isRubricName(name, editorCfg);
                }) ||
            std::any_of(altayShort.begin(), altayShort.end(),
                [&](const auto& name) {
                    return isRubricName(name, editorCfg);
                }))
        {
            ++namesStat.withRubricNames;
        }
        if (std::any_of(altayShort.begin(), altayShort.end(),
                [&](const auto& shortName) {
                    return 0 < altayFull.count(shortName);
                }))
        {
            ++namesStat.withSomeShortInFull;
        }
        const Names altayNames(patch);
        const Names nmapsNames(*nmapsObject);
        const auto& altayLangs = altayNames.langs();
        const auto& nmapsLangs = nmapsNames.langs();
        if (altayLangs.size() > nmapsLangs.size()) {
            ++namesStat.altayLangsGreater;
        } else if (altayLangs.size() < nmapsLangs.size()) {
            ++namesStat.altayLangsLess;
        } else if (altayNames.size() == nmapsNames.size()) {
            ++namesStat.sameCountLangsAndNames;
        }
    }
    return namesStat;
}

} // namespace maps::wiki::merge_poi
