#include <library/cpp/testing/unittest/registar.h>

#include <wmconsole/version3/processors/indexing/important_urls/task_update.h>
#include <wmconsole/version3/processors/indexing/important_urls/task_update.cpp>
#include <wmconsole/version3/wmcutil/yt/mock.h>

using namespace NWebmaster;
using namespace NWebmaster::NImportantUrls;

namespace {
    const char *F_DESCRIPTION_CHANGED  = "_Changed_Description";
    //const char *F_DESCRIPTION          = "Description";
    //const char *F_HOST                 = "Host";
    //const char *F_TITLE                = "Title";
    //const char *F_PATH                 = "Path";
    //const char *F_URL                  = "Url";
    //const char *F_USER_ID              = "UserId";
    const char *F_IN_DESCRIPTION       = "MetaDescription";
    const char *F_IN_TITLE             = "TitleRawUTF8";
}

Y_UNIT_TEST_SUITE(TImportantUrlsReducer) {
    static void AssertDescriptionChanged(const bool changed, const TVector<TVector<NYT::TNode>> &outputNodes) {
        const size_t SNAPSHOT_IDX = 1;
        UNIT_ASSERT_EQUAL(2, outputNodes.size());
        const auto &snapshotTable = outputNodes[SNAPSHOT_IDX];
        UNIT_ASSERT_EQUAL(1, snapshotTable.size());
        const NYT::TNode &snapshot = snapshotTable[0].AsMap();
        UNIT_ASSERT_EQUAL(changed, snapshot[F_DESCRIPTION_CHANGED].AsBool());
    }


    static TVector<TVector<NYT::TNode>> DoReduce(const TDeque<TImportantUrlsConfig> &inputConfig,
                                          const TVector<NYT::TNode> &inputNodes) {
        TVector<TVector<NYT::TNode>> outputNodes(2);
        NYT::TTableReader<NYT::TNode> input(new NWebmaster::NYTUtils::TReaderMockImpl(inputNodes));
        NYT::TTableWriter<NYT::TNode> output(new NWebmaster::NYTUtils::TWriterMockImpl(outputNodes));
        TImportantUrlsReducer reducer(inputConfig);
        reducer.Do(&input, &output);
        return outputNodes;
    }

    Y_UNIT_TEST(DescriptionUpdatedIfNewDescription) {
        {
            const TDeque<TImportantUrlsConfig> inputConfig = {
                    TImportantUrlsConfig(TImportantUrlsConfig::E_TABLE_IMPORTANT_URLS),
                    TImportantUrlsConfig(TImportantUrlsConfig::E_TABLE_SNAPSHOT),
                    TImportantUrlsConfig(TImportantUrlsConfig::E_TABLE_CONTENT_ATTRS),
            };
            const TVector<NYT::TNode> inputNodes{
                    NYT::TNode()(F_HOST, "host")(F_PATH, "path")(F_URL, "url"),
                    NYT::TNode()(F_TITLE, "old title")(F_DESCRIPTION, NYT::TNode::CreateEntity()),
                    NYT::TNode()(F_IN_DESCRIPTION, "new description")(F_IN_TITLE, "new title")
            };

            const TVector<TVector<NYT::TNode>> outputNodes = DoReduce(inputConfig, inputNodes);

            AssertDescriptionChanged(true, outputNodes);
        }
        {
            const TDeque<TImportantUrlsConfig> inputConfig = {
                    TImportantUrlsConfig(TImportantUrlsConfig::E_TABLE_IMPORTANT_URLS),
                    TImportantUrlsConfig(TImportantUrlsConfig::E_TABLE_SNAPSHOT),
                    TImportantUrlsConfig(TImportantUrlsConfig::E_TABLE_CONTENT_ATTRS),
            };
            const TVector<NYT::TNode> inputNodes {
                    NYT::TNode()(F_HOST, "host")(F_PATH, "path")(F_URL, "url"),
                    NYT::TNode()(F_TITLE, "old title")(F_DESCRIPTION, "old description"),
                    NYT::TNode()(F_IN_DESCRIPTION, NYT::TNode::CreateEntity())(F_IN_TITLE, "new title")
            };

            const TVector<TVector<NYT::TNode>> outputNodes = DoReduce(inputConfig, inputNodes);

            AssertDescriptionChanged(true, outputNodes);
        }
        {
            const TDeque<TImportantUrlsConfig> inputConfig = {
                    TImportantUrlsConfig(TImportantUrlsConfig::E_TABLE_IMPORTANT_URLS),
                    TImportantUrlsConfig(TImportantUrlsConfig::E_TABLE_SNAPSHOT),
                    TImportantUrlsConfig(TImportantUrlsConfig::E_TABLE_CONTENT_ATTRS),
            };
            const TVector<NYT::TNode> inputNodes {
                    NYT::TNode()(F_HOST, "host")(F_PATH, "path")(F_URL, "url"),
                    NYT::TNode()(F_TITLE, "old title")(F_DESCRIPTION, "old description"),
                    NYT::TNode()(F_IN_DESCRIPTION, "new description")(F_IN_TITLE, "new title")
            };

            const TVector<TVector<NYT::TNode>> outputNodes = DoReduce(inputConfig, inputNodes);

            AssertDescriptionChanged(true, outputNodes);
        }
    }
}

Y_UNIT_TEST_SUITE(TImportantUrlsPathConvertMapper) {
    Y_UNIT_TEST(AssertMapperOutput) {
        const TString firstHost = "http://ya.ru";
        const TString firstPath = "/some-path";
        const TString secondHost = "https://www.ya.ru";
        const TString secondPath = "/another-path";
        const TString secondUser = "SomeUser";
        const TVector<NYT::TNode> inputNodes {
                NYT::TNode()(F_URL, firstHost + firstPath),
                NYT::TNode()(F_URL, secondHost + secondPath)(F_USER_ID, secondUser),
        };
        NYT::TTableReader<NYT::TNode> input(new NWebmaster::NYTUtils::TReaderMockImpl(inputNodes));

        TVector<TVector<NYT::TNode>> outputNodes(1);
        NYT::TTableWriter<NYT::TNode> output(new NWebmaster::NYTUtils::TWriterMockImpl(outputNodes));


        TImportantUrlsPathConvertMapper mapper;
        mapper.Do(&input, &output);


        UNIT_ASSERT_EQUAL(1, outputNodes.size());
        const auto &table = outputNodes[0];
        const auto &first = table[0];

        UNIT_ASSERT_EQUAL(inputNodes.size(), table.size());
        UNIT_ASSERT_EQUAL(firstHost, first[F_HOST].AsString());
        UNIT_ASSERT_EQUAL(firstPath, first[F_PATH].AsString());
        UNIT_ASSERT_EQUAL(true, first[F_USER_ID].IsEntity());

        const auto &second = table[1];
        UNIT_ASSERT_EQUAL(secondHost, second[F_HOST].AsString());
        UNIT_ASSERT_EQUAL(secondPath, second[F_PATH].AsString());
        UNIT_ASSERT_EQUAL(secondUser, second[F_USER_ID].AsString());
    }
}
