#pragma once

#include <balancer/kernel/helpers/helper_macro.h>

#include <util/generic/maybe.h>
#include <util/generic/strbuf.h>
#include <util/generic/string.h>
#include <util/memory/blob.h>
#include <util/string/split.h>
#include <util/string/strip.h>

#include <string>
#include <tuple>

namespace NSrvKernel::NCookie {
    inline TStringBuf SkipDot(TStringBuf domain) noexcept {
        return domain.size() > 0 && domain[0] == '.' ? domain.Skip(1) : domain;
    }

    inline TStringBuf RSkipDot(TStringBuf domain) noexcept {
        return domain.size() > 0 && domain.back() == '.' ? domain.Chop(1) : domain;
    }

    inline TStringBuf StripPort(TStringBuf domainPort) noexcept {
        return domainPort.RBefore(':');
    }

    inline TStringBuf ToStringBuf(const TBlob& b) {
        return {(const char*)b.Data(), b.Size()};
    }

    // TBlob is a powerful abstraction but its interface sucks
    inline TBlob FromStringBuf(TStringBuf sb) {
        return TBlob::NoCopy(sb.data(), sb.size());
    }

    inline TStringBuf StrToLower(std::string& res, TStringBuf str) noexcept {
        // Does not allocate if str is less than 23 bytes long
        res.clear();
        res.resize_uninitialized(str.size());
        for (ui64 i = 0; i < str.size(); ++i) {
            ui8 c = str[i];
            res[i] = c + ('a' - 'A') * ((c >= 'A') & (c <= 'Z'));
        }
        return res;
    }

    inline std::string StrToLower(TStringBuf str) noexcept {
        std::string res;
        StrToLower(res, str);
        return res;
    }

    inline void PrintTo(IOutputStream& out, const TMaybe<TStringBuf>& v) noexcept {
        if (v) {
            out << TString(*v).Quote();
        } else {
            out << "Nothing()"sv;
        }
    }

    inline void PrintTo(IOutputStream& out, const TMaybe<TString>& v) noexcept {
        PrintTo(out, TMaybe<TStringBuf>(v));
    }

    inline void PrintTo(IOutputStream& out, const TMaybe<std::string>& v) noexcept {
        PrintTo(out, TMaybe<TStringBuf>(v));
    }

    template <class TVal>
    void PrintTo(IOutputStream& out, const TMaybe<TVal>& v) noexcept {
        if (v) {
            out << *v;
        } else {
            out << "Nothing()"sv;
        }
    }
}
