#include <maps/libs/common/include/exception.h>
#include <maps/libs/log8/include/log8.h>
#include <maps/libs/cmdline/include/cmdline.h>
#include <maps/libs/common/include/exception.h>

#include <mapreduce/yt/interface/client.h>
#include <util/charset/utf8.h>
#include <util/charset/wide.h>

#include <random>
#include <string>
#include <list>
#include <fstream>
#include <iostream>

using namespace NYT;

int main(int argc, const char** argv) try {
    static const TString YT_PROXY = "hahn";
    static const TString YT_TABLE_PATH = "//home/maps/core/garden/stable/ymapsdf/latest/";
    static const TString YT_TABLE_NAME = "addr_nm";

    static const TString COL_NAME = "name";

    Initialize(argc, argv);

    maps::cmdline::Parser parser("Calculate house number symbols statistic");

    maps::cmdline::Option<std::string> regionsCodeParam = parser.string("regions")
        .defaultValue("eu1")
        .help("Regions codes divided by commas for table (default: eu1)");

    maps::cmdline::Option<int> minCountForPrint = parser.num("min-count")
        .defaultValue(0)
        .help("Minimal amount of symbol in address points names. (default: 0)");


    parser.parse(argc, const_cast<char**>(argv));

    std::vector<std::string> regionsCode;
    {
        std::stringstream ss(regionsCodeParam);
        std::string code;
        while (std::getline(ss, code, ',')) {
            regionsCode.push_back(code);
        }
    }

    INFO() << "Connecting to yt::" << YT_PROXY;
    IClientPtr client = CreateClient(YT_PROXY);

    std::map< wchar16, uint64_t> statistic;
    for (const std::string& code : regionsCode) {
        INFO() << "Rework region code: " << code;
        const TString addrNameTable = YT_TABLE_PATH + code +  "/" + YT_TABLE_NAME;
        TTableReaderPtr<TNode> reader = client->CreateTableReader<TNode>(addrNameTable);
        for (int processedItems = 0; reader->IsValid(); reader->Next(), processedItems++) {
            if ((processedItems + 1) % 1000000 == 0) {
                INFO() << "Processed " << (processedItems + 1) << " items";
            }
            const TNode& inpRow = reader->GetRow();
            const TUtf16String name = UTF8ToWide(inpRow[COL_NAME].AsString());
            for (size_t i = 0; i < name.size(); i++) {
                statistic[name[i]]++;
            }
        };
    }

    std::vector< std::pair<wchar16, uint64_t> > statSorted;
    for (const auto& stat : statistic) {
        statSorted.push_back({stat.first, stat.second});
    }
    std::sort(statSorted.begin(), statSorted.end(),
        [](const std::pair<wchar16, uint64_t>& a, const std::pair<wchar16, uint64_t>& b) {
            return a.second > b.second;
        }
    );
    for (const auto& stat : statSorted) {
        if (stat.second <= (uint64_t)minCountForPrint)
            break;
        const TUtf16String char_(&stat.first, 1);
        INFO() << WideToUTF8(char_) << " | "
               << (int)stat.first <<   " | "
               << stat.second;
    }

    return EXIT_SUCCESS;
}
catch (const maps::Exception& e) {
    FATAL() << "Tools failed: " << e;
    return EXIT_FAILURE;
}
catch (const std::exception& e) {
    FATAL() << "Tools failed: " << e.what();
    return EXIT_FAILURE;
}
