#include "ut_common.h"

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

#include <util/generic/xrange.h>

namespace NSrvKernel::NCookie {

    void TestParse(TString input, TSetCookie::TParseResult result, TMaybe<TString> render) {
        const auto cc = TSetCookie::Parse(FromStringBuf(input));
        std::visit(TOverloaded{
            [&](const TSetCookie& nv) {
                UNIT_ASSERT_C(std::holds_alternative<TSetCookie>(cc), input.Quote());
                const auto c = std::get<TSetCookie>(cc);
                UNIT_ASSERT_VALUES_EQUAL_C(c.Name, nv.Name, input.Quote());
                UNIT_ASSERT_VALUES_EQUAL_C(ToStringBuf(c.Value), ToStringBuf(nv.Value), input.Quote());
                UNIT_ASSERT_VALUES_EQUAL_C(c.Path, nv.Path, input.Quote());
                UNIT_ASSERT_VALUES_EQUAL_C(c.Domain, nv.Domain, input.Quote());
                UNIT_ASSERT_VALUES_EQUAL_C(c.Expires, nv.Expires, input.Quote());
                UNIT_ASSERT_VALUES_EQUAL_C(c.MaxAge, nv.MaxAge, input.Quote());
                UNIT_ASSERT_VALUES_EQUAL_C(c.SameSite, nv.SameSite, input.Quote());
                UNIT_ASSERT_VALUES_EQUAL_C(c.Secure, nv.Secure, input.Quote());
                UNIT_ASSERT_VALUES_EQUAL_C(c.HttpOnly, nv.HttpOnly, input.Quote());
                TestRender(c, render ? *render : input);
            },
            [&](TSetCookieSyntaxErrors errs) {
                UNIT_ASSERT_C(std::holds_alternative<TSetCookieSyntaxErrors>(cc), input.Quote());
                const auto c = std::get<TSetCookieSyntaxErrors>(cc);
                for (auto err : xrange(GetEnumItemsCount<ESetCookieSyntaxError>())) {
                    UNIT_ASSERT_VALUES_EQUAL_C(
                        c.Get(ESetCookieSyntaxError(err)),
                        errs.Get(ESetCookieSyntaxError(err)),
                        ESetCookieSyntaxError(err) << " " << input.Quote()
                    );
                }
            }
        }, result);
    }

    void TestRender(const TSetCookie& c, TStringBuf expected) {
        auto b = c.Render();
        UNIT_ASSERT_VALUES_EQUAL(ToStringBuf(b), expected);
        auto c2 = TSetCookie::Parse(b);
        UNIT_ASSERT_C(std::holds_alternative<TSetCookie>(c2), TString(ToStringBuf(b)).Quote());
        UNIT_ASSERT_VALUES_EQUAL(std::get<TSetCookie>(c2), c);
        auto b2 = std::get<TSetCookie>(c2).Render();
        UNIT_ASSERT_VALUES_EQUAL(ToStringBuf(b2), expected);
    }

    void TestEveryCookieKV(TStringBuf cookie, const TCookieVec& expected) {
        using namespace NSrvKernel;
        TCookieVec res;

        EveryCookieKV([&](TNameValue nv) {
            res.emplace_back(nv);
        }, cookie);

        UNIT_ASSERT_VALUES_EQUAL(res, expected);
    }
}
