#pragma once

#include <library/cpp/regex/pire/regexp.h>
#include <balancer/kernel/helpers/default_instance.h>
#include <balancer/kernel/http/parser/http.h>

namespace NWebAuth {
struct TTokenFsm : public NRegExp::TFsm, public NSrvKernel::TWithDefaultInstance<TTokenFsm> {
    TTokenFsm() noexcept
        : TFsm("webauth-csrf-token",  NRegExp::TFsm::TOptions().SetCaseInsensitive(true))
    {}
};

struct TStateFsm : public NRegExp::TFsm, public NSrvKernel::TWithDefaultInstance<TStateFsm> {
    TStateFsm() noexcept
        : TFsm("webauth-csrf-state",  NRegExp::TFsm::TOptions().SetCaseInsensitive(true))
    {}
};

struct TAppIdFsm : public NRegExp::TFsm, public NSrvKernel::TWithDefaultInstance<TAppIdFsm> {
    TAppIdFsm() noexcept
        : TFsm("webauth-oauth-app-id",  NRegExp::TFsm::TOptions().SetCaseInsensitive(true))
    {}
};

struct THeaderMatcher {
    THeaderMatcher() noexcept = default;

    TMaybe<TStringBuf> AppId() noexcept {
        return AppId_;
    }

    TMaybe<TStringBuf> State() noexcept {
        return State_;
    }

    TMaybe<TStringBuf> Token() noexcept {
        return Token_;
    }

    void Match(const NSrvKernel::THeaders& headers) noexcept {
        for (const auto& hdr : headers) {
            NRegExp::TMatcher matcher(TAuthHeadersFsm::Instance());
            if (!NSrvKernel::Match(matcher, hdr.first.AsStringBuf()).Final()) {
                continue;
            }
            switch (*matcher.MatchedRegexps().first) {
                case 0:
                    Token_ = hdr.second.back().AsStringBuf();
                    break;
                case 1:
                    State_ = hdr.second.back().AsStringBuf();
                    break;
                case 2:
                    AppId_ = hdr.second.back().AsStringBuf();
                    break;
            }
        }
    }

private:

    struct TAuthHeadersFsm : public NRegExp::TFsm, public NSrvKernel::TWithDefaultInstance<TAuthHeadersFsm> {
        TAuthHeadersFsm() noexcept
            : TFsm(TTokenFsm::Instance() | TStateFsm::Instance() | TAppIdFsm::Instance())
        {}
    };

    TMaybe<TStringBuf> AppId_;
    TMaybe<TStringBuf> State_;
    TMaybe<TStringBuf> Token_;
};
}
