#pragma once

#include <balancer/kernel/http/parser/http.h>
#include <util/generic/string.h>
#include <util/generic/vector.h>
#include <balancer/kernel/memory/chunks.h>
#include <library/cpp/digest/murmur/murmur.h>
#include <util/generic/queue.h>


namespace NSrvKernel::NStorage {
    class TStorageKey {
    public:
        TString Path_;
        TString CGI_;
        TString AcceptEncoding_;
    private:
        mutable TMaybe<size_t> CalculatedHash_;

    public:
        TStorageKey (TString path, TString cgi, TString acceptEncoding) {
            Path_ = std::move(path);
            CGI_ = std::move(cgi);
            AcceptEncoding_ = std::move(acceptEncoding);
        }

        operator size_t () const {
            if (CalculatedHash_.Defined()) {
                return *CalculatedHash_;
            }

            TMurmurHash2A<size_t> hash;

            hash.Update(Path_.Data(), Path_.Size());
            hash.Update(CGI_.Data(), CGI_.Size());
            hash.Update(AcceptEncoding_.Data(), AcceptEncoding_.Size());

            CalculatedHash_ = hash.Value();

            return *CalculatedHash_;
        }

        bool operator == (const TStorageKey& key) const {
            return key.Path_ == Path_ && key.CGI_ == CGI_ && key.AcceptEncoding_ == AcceptEncoding_;
        }
    };

    class TKeyGenerator {
    private:
        bool IgnoreCGI = true;
    public:
        void SetIgnoreCGI (bool ignoreCGI) {
            IgnoreCGI = ignoreCGI;
        }

        TStorageKey Generate (const TRequest& re) const {
            const auto header = re.Headers().FindValues("accept-encoding");
            if (header != re.Headers().End()) {
                for (auto& value : header->second) {
                    if (IgnoreCGI) {
                        return TStorageKey(TString(re.RequestLine().Path.AsStringBuf()), TString()/*TString(re.RequestLine().CGI.AsStringBuf())*/, TString(value.AsStringBuf()));
                    }

                    return TStorageKey(TString(re.RequestLine().Path.AsStringBuf()), TString(re.RequestLine().CGI.AsStringBuf()), TString(value.AsStringBuf()));
                }
            }

            if (IgnoreCGI) {
                return TStorageKey(TString(re.RequestLine().Path.AsStringBuf()), TString()/*TString(re.RequestLine().CGI.AsStringBuf())*/, TString());
            }

            return TStorageKey(TString(re.RequestLine().Path.AsStringBuf()), TString(re.RequestLine().CGI.AsStringBuf()), TString());
        }
    };
}
