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

Y_UNIT_TEST_SUITE(TResponseMatcher) {
    using namespace NSrvKernel;

    THolder<IResponseMatcher> CreateMatcher(const TString key, const TString config) {
        TMemoryInput stream(config);
        auto conf = NConfig::ConfigParser(stream);
        return ConstructResponseMatcher(nullptr, key, conf.Get());
    }
    struct TResponseHolder {
        TResponseHolder() {
            Response.ResponseLine().StatusCode = 200;
            Response.Headers().Add("Location", "https://yabs.yandex.ru/full_match");
        }

        TResponse Response;
    };

    void MatchDefaultResponse(const TString name, const TString config, bool match) {
        auto matcher = CreateMatcher(name, config);
        UNIT_ASSERT(matcher);
        UNIT_ASSERT_VALUES_EQUAL_C(matcher->Match(Default<TResponseHolder>().Response), match, config);
    }

    Y_UNIT_TEST(TestHeaderMatcher) {
        UNIT_ASSERT_EXCEPTION(CreateMatcher("match_header", "instance = { name = 'x-real-ip'; }"), NConfig::TConfigParseError);
        UNIT_ASSERT_EXCEPTION(CreateMatcher("match_header", "instance = { value = '.*'; }"), NConfig::TConfigParseError);
        UNIT_ASSERT_EXCEPTION(CreateMatcher("match_header", "instance = {}"), NConfig::TConfigParseError);

        MatchDefaultResponse("match_header", "instance = { name = 'x-real-ip'; value = '.*' }", false);
        MatchDefaultResponse("match_header", "instance = { name = 'Location'; value = 'yabs.yandex.ru' }", false);
        MatchDefaultResponse("match_header", "instance = { name = 'Location'; value = 'https://Yabs.Yandex.ru.*' }", false);

        // TODO(velavokr): BALANCER-3103 if this regexp is fixed the next one is broken
        // MatchDefaultResponse("match_header", "instance = { name = 'location'; value = '^.*$' }", true);
        MatchDefaultResponse("match_header", "instance = { name = 'location'; value = '.*' }", true);
        MatchDefaultResponse("match_header", "instance = { name = 'LoCaTiOn'; value = '.*' }", true);
        MatchDefaultResponse("match_header", "instance = { name = 'Location'; value = 'https://yabs.yandex.ru.*' }", true);
        MatchDefaultResponse("match_header", "instance = { name = 'Location'; value = 'https://Yabs.Yandex.ru.*'; value_case_insensitive=true; }", true);
        MatchDefaultResponse("match_header", "instance = { name = 'Location'; value = 'https://yabs.yandex.ru/full_match'; }", true);
        MatchDefaultResponse("match_header", "instance = { name = ' Location   '; value = '  https://yabs.yandex.ru/full_match   ' }", true);
    }

    Y_UNIT_TEST(TestCodesMatcher) {
        UNIT_ASSERT_EXCEPTION(CreateMatcher("match_response_codes", "instance = { codes = {10} }"), NConfig::TConfigParseError);
        UNIT_ASSERT_EXCEPTION(CreateMatcher("match_response_codes", "instance = { codes = {600} }"), NConfig::TConfigParseError);
        UNIT_ASSERT_EXCEPTION(CreateMatcher("match_response_codes", "instance = { }"), NConfig::TConfigParseError);

        MatchDefaultResponse("match_response_codes", "instance = { codes = {200}; }", true);
        MatchDefaultResponse("match_response_codes", "instance = { codes = {200, 204, 400 }; }", true);
        MatchDefaultResponse("match_response_codes", "instance = { codes = {400}; }", false);
    }

    Y_UNIT_TEST(TestOperations) {
        UNIT_ASSERT_EXCEPTION(CreateMatcher("match_not", "instance = { }"), NConfig::TConfigParseError);
        UNIT_ASSERT_EXCEPTION(CreateMatcher("match_and", "instance = { }"), NConfig::TConfigParseError);
        UNIT_ASSERT_EXCEPTION(CreateMatcher("match_or", "instance = { }"), NConfig::TConfigParseError);

        MatchDefaultResponse("match_all", "instance = { }", true);
        MatchDefaultResponse("match_not", "instance = { match_all = {} }", false);
        MatchDefaultResponse("match_or", "instance = {{ match_not = { match_all = {} }};  { match_all = {};} }", true);
        MatchDefaultResponse("match_or", "instance = {{ match_not = { match_all = {} }};  { match_not = { match_all = {}}} }", false);
        MatchDefaultResponse("match_and", "instance = {{ match_not = { match_all = {} }};  { match_all = {};} }", false);
    }
}
