#include <balancer/kernel/http/headers.h>

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

using namespace NSrvKernel;
Y_UNIT_TEST_SUITE(THttpHeadersTest) {
    Y_UNIT_TEST(TestHeadersIter) {

        THeaders from;
        from.Add("xxxK", "xxxV");
        from.Add("yyyK", "yyyV");
        from.Add("yyyK2","yyyV2");
        from.Add("zzzK", "zzzV");

        THeaders to;

        EraseNodesIf(from, [&to](auto& header){
            if (header.first.AsStringBuf() != "yyyK2") {
                for (const auto& v : header.second) {
                    to.Add(header.first.AsString(), v.AsString());
                }
            }
            return true;
        });

        UNIT_ASSERT_VALUES_EQUAL(from.Size(), 0u);
        UNIT_ASSERT_VALUES_EQUAL(to.Size(), 3u);
        UNIT_ASSERT_VALUES_EQUAL(to.GetFirstValue(TFsm{"xxxK"}), "xxxV");
        UNIT_ASSERT_VALUES_EQUAL(to.GetFirstValue(TFsm{"yyyK"}), "yyyV");
        UNIT_ASSERT_VALUES_EQUAL(to.GetFirstValue(TFsm{"zzzK"}), "zzzV");
        UNIT_ASSERT_VALUES_EQUAL(to.GetFirstValue(TFsm{"yyyK2"}).empty(), true);
    }


    Y_UNIT_TEST(TestHeadersParsing) {
        THeaders h;
        h.Add("ABC", "def");
        h.Add("qew", "jdy");
        h.Add("aabb", "ews");
    }

    Y_UNIT_TEST(TestHeadersCopy) {
        THeaders headers;

        headers.Add("h1", "v1");
        headers.Add("h2", "v2");
        headers.Add("h3", "v3");
        headers.Add("h4", "v4.1");
        headers.Add("h4", "v4.2");

        UNIT_ASSERT_EQUAL(headers.GetValuesRef("H1").size(), 1u);
        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h1").front(), "v1");
        UNIT_ASSERT_EQUAL(headers.GetValuesRef("H2").size(), 1u);
        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h2").front(), "v2");
        UNIT_ASSERT_EQUAL(headers.GetValuesRef("H3").size(), 1u);
        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h3").front(), "v3");
        UNIT_ASSERT_EQUAL(headers.GetValuesRef("H4").size(), 2u);
        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h4").front(), "v4.1");
        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h4")[1], "v4.2");
        UNIT_ASSERT(headers.GetValuesRef("h5").empty());
        UNIT_ASSERT_EQUAL(headers.Size(), 5u);

        UNIT_ASSERT_EQUAL(headers.GetFirstValue(TFsm{"h1"}), "v1");
        UNIT_ASSERT_EQUAL(headers.GetFirstValue(TFsm{"h2"}), "v2");
        UNIT_ASSERT_EQUAL(headers.GetFirstValue(TFsm{"h3"}), "v3");
        UNIT_ASSERT_EQUAL(headers.GetFirstValue(TFsm{"h4"}), "v4.1");
        UNIT_ASSERT_EQUAL(headers.GetFirstValue(TFsm{"h5"}), "");
        UNIT_ASSERT_EQUAL(headers.Size(), 5u);

        THeaders headers2 = std::move(headers);

        UNIT_ASSERT_EQUAL(headers2.GetValuesRef("H1").size(), 1u);
        UNIT_ASSERT_EQUAL(headers2.GetValuesRef("h1").front(), "v1");
        UNIT_ASSERT_EQUAL(headers2.GetValuesRef("H2").size(), 1u);
        UNIT_ASSERT_EQUAL(headers2.GetValuesRef("h2").front(), "v2");
        UNIT_ASSERT_EQUAL(headers2.GetValuesRef("H3").size(), 1u);
        UNIT_ASSERT_EQUAL(headers2.GetValuesRef("h3").front(), "v3");
        UNIT_ASSERT_EQUAL(headers2.GetValuesRef("h4").size(), 2u);
        UNIT_ASSERT_EQUAL(headers2.GetValuesRef("h4").front(), "v4.1");
        UNIT_ASSERT_EQUAL(headers2.GetValuesRef("h4")[1], "v4.2");
        UNIT_ASSERT(headers2.GetValuesRef("h5").empty());
        UNIT_ASSERT_EQUAL(headers2.Size(), 5u);

        THeaders headers3 = headers2;

        UNIT_ASSERT_EQUAL(headers3.GetValuesRef("h1").size(), 1u);
        UNIT_ASSERT_EQUAL(headers3.GetValuesRef("h1").front(), "v1");
        UNIT_ASSERT_EQUAL(headers3.GetValuesRef("h2").size(), 1u);
        UNIT_ASSERT_EQUAL(headers3.GetValuesRef("h2").front(), "v2");
        UNIT_ASSERT_EQUAL(headers3.GetValuesRef("h3").size(), 1u);
        UNIT_ASSERT_EQUAL(headers3.GetValuesRef("h3").front(), "v3");
        UNIT_ASSERT_EQUAL(headers3.GetValuesRef("h4").size(), 2u);
        UNIT_ASSERT_EQUAL(headers3.GetValuesRef("h4").front(), "v4.1");
        UNIT_ASSERT(headers2.GetValuesRef("h5").empty());
        UNIT_ASSERT_EQUAL(headers3.Size(), 5u);

        auto iter1 = headers3.FindValues(TFsm{"h3"});

        UNIT_ASSERT_EQUAL(iter1->first, "h3");
        UNIT_ASSERT_EQUAL(iter1->second.front(), "v3");

        headers3.erase(iter1);
        headers3.erase(headers3.FindValues("H4"));

        UNIT_ASSERT_EQUAL(headers3.GetValuesRef("h1").size(), 1u);
        UNIT_ASSERT_EQUAL(headers3.GetValuesRef("h1").front(), "v1");
        UNIT_ASSERT_EQUAL(headers3.GetValuesRef("H2").size(), 1u);
        UNIT_ASSERT_EQUAL(headers3.GetValuesRef("h2").front(), "v2");
        UNIT_ASSERT(headers3.GetValuesRef("h3").empty());
        UNIT_ASSERT(headers3.GetValuesRef("h4").empty());
        UNIT_ASSERT_EQUAL(headers3.Size(), 2u);

        headers3.Add("h3", "v3");
        headers3.Add("h4", "v4.1");
        headers3.Add("h4", "v4.2");

        headers3.Delete(TFsm{"h4"});
        headers3.Delete("H4");
        headers3.Delete("H3");
        headers3.Delete(TFsm{"h3"});

        UNIT_ASSERT_EQUAL(headers3.GetValuesRef("h1").size(), 1u);
        UNIT_ASSERT_EQUAL(headers3.GetValuesRef("h1").front(), "v1");
        UNIT_ASSERT_EQUAL(headers3.GetValuesRef("h2").size(), 1u);
        UNIT_ASSERT_EQUAL(headers3.GetValuesRef("h2").front(), "v2");
        UNIT_ASSERT(headers3.GetValuesRef("h3").empty());
        UNIT_ASSERT(headers3.GetValuesRef("h4").empty());
        UNIT_ASSERT_EQUAL(headers3.Size(), 2u);

        THeaders headers4;

        headers4.Add("h1", "v1.1");
        headers4.Add("h1", "v1.2");

        THeaders headers5;
        headers5.Add("h2", "v2.1");
        headers5.Add("h2", "v2.2");
        headers5.Add("h3", "v3.1");
        headers5.Add("h3", "v3.2");

        UNIT_ASSERT_EQUAL(headers5.Size(), 4u);
        UNIT_ASSERT_EQUAL(headers4.Size(), 2u);

        headers5.Swap(headers4);

        UNIT_ASSERT_EQUAL(headers4.Size(), 4u);
        UNIT_ASSERT_EQUAL(headers5.Size(), 2u);

        UNIT_ASSERT_EQUAL(headers5.GetValuesRef("h1").size(), 2u);
        UNIT_ASSERT_EQUAL(headers5.GetValuesRef("h1")[0], "v1.1");
        UNIT_ASSERT_EQUAL(headers5.GetValuesRef("h1")[1], "v1.2");
        UNIT_ASSERT_EQUAL(headers4.GetValuesRef("h2").size(), 2u);
        UNIT_ASSERT_EQUAL(headers4.GetValuesRef("h2")[0], "v2.1");
        UNIT_ASSERT_EQUAL(headers4.GetValuesRef("h2")[1], "v2.2");
        UNIT_ASSERT_EQUAL(headers4.GetValuesRef("h3").size(), 2u);
        UNIT_ASSERT_EQUAL(headers4.GetValuesRef("h3")[0], "v3.1");
        UNIT_ASSERT_EQUAL(headers4.GetValuesRef("h3")[1], "v3.2");

        headers5.Delete("H1");
        UNIT_ASSERT_EQUAL(headers5.Size(), 0u);
        headers5.Delete("H2");
        UNIT_ASSERT_EQUAL(headers5.Size(), 0u);
        headers4.Delete("H2");
        UNIT_ASSERT_EQUAL(headers4.Size(), 2u);
        headers4.Delete("H3");
        UNIT_ASSERT_EQUAL(headers4.Size(), 0u);
    }

    Y_UNIT_TEST(TestHeaderGetValues) {
        THeaders headers;
        headers.Add("h", TString{"w1"});
        TString value("w2");
        headers.Add("h", TStringBuf{value});

        {
            auto values = headers.GetValuesRef("h");
            UNIT_ASSERT_EQUAL(values.size(), 2u);
            UNIT_ASSERT_EQUAL(values[0], "w1");
            UNIT_ASSERT_EQUAL(values[1], "w2");
            value[1] = '3';
            UNIT_ASSERT_EQUAL(values[1], "w3");
        }

        {
            auto values = headers.GetValues("h");
            UNIT_ASSERT_EQUAL(values.size(), 2u);
            UNIT_ASSERT_EQUAL(values[0], "w1");
            UNIT_ASSERT_EQUAL(values[1], "w3");
            value[1] = '4';
            UNIT_ASSERT_EQUAL(values[1], "w3");
        }

        {
            auto values = headers.GetValuesMove("h");
            UNIT_ASSERT_EQUAL(values.size(), 2u);
            UNIT_ASSERT_EQUAL(values[0], "w1");
            UNIT_ASSERT_EQUAL(values[1], "w4");
            value[1] = '5';
            UNIT_ASSERT_EQUAL(values[1], "w4");
        }
    }

    Y_UNIT_TEST(TestHeaderAdd) {
        THeaders headers;
        headers.Add("h", "w1");
        headers.Add("h", "w2");

        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h").size(), 2u);
        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h")[0], "w1");
        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h")[1], "w2");
    }

    Y_UNIT_TEST(TestHeaderAddEmpty) {
        THeaders headers;
        headers.Add("h", "w1");
        headers.Add("h", "");

        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h").size(), 2u);
        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h")[0], "w1");
        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h")[1], "");
    }

    Y_UNIT_TEST(TestHeaderReplace) {
        THeaders headers;
        headers.Add("h", "w1");
        headers.Replace("h", "w2");

        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h").size(), 1u);
        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h")[0], "w2");
    }

    Y_UNIT_TEST(TestHeaderReplaceEmpty) {
        THeaders headers;
        headers.Add("h", "w1");
        headers.Replace("h", "");

        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h").size(), 1u);
        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h")[0], "");
    }

    Y_UNIT_TEST(TestHeadersAdd) {
        THeaders headers;
        headers.Add("h", TStringStorage{"w1"});
        headers.Add("h", TVector<TStringStorage>{TStringStorage{"w2"}, TStringStorage{"w3"}});

        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h").size(), 3u);
        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h")[0], "w1");
        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h")[1], "w2");
        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h")[2], "w3");
    }

    Y_UNIT_TEST(TestHeadersAddEmpty) {
        THeaders headers;
        headers.Add("h", TStringStorage{"w1"});
        headers.Add("h", {});

        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h").size(), 1u);
        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h")[0], "w1");
    }

    Y_UNIT_TEST(TestHeadersReplace) {
        THeaders headers;
        headers.Add("h", TStringStorage{"w1"});
        headers.Replace("h", TVector<TStringStorage>{TStringStorage{"w2"}, TStringStorage{"w3"}});

        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h").size(), 2u);
        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h")[0], "w2");
        UNIT_ASSERT_EQUAL(headers.GetValuesRef("h")[1], "w3");
    }

    Y_UNIT_TEST(TestHeadersReplaceEmpty) {
        THeaders headers;
        headers.Add("h", TStringStorage{"w1"});
        headers.Replace("h", {});

        UNIT_ASSERT(headers.FindValues("h") == headers.end());
    }
};
