#include "p_samesite_none.h"

#include <balancer/kernel/client_hints/impl/client_hints.h>
#include <balancer/modules/cookie_policy/common/utils.h>

namespace NModCookiePolicy {
    TPolicySameSiteNone::TPolicySameSiteNone(TString name, const TPolicySameSiteNoneCfg& cfg)
        : ICookiePolicy(name, cfg.mode())
        , Cfg_(cfg)
        , NameRe_(MaybeRe(cfg.name_re(), cfg.has_name_re()))
    {}

    bool TPolicySameSiteNone::MatchResponseCookie(const TSetCookie& c, const TPolicyArgs&) const noexcept {
        return c.SameSite == ESameSite::None || NameRe_ && Match(*NameRe_, c.Name);
    }

    TMaybe<ICookiePolicy::TAction> TPolicySameSiteNone::ApplyToResponseCookie(
        TResponseCookieView c, const TPolicyArgs& args) const noexcept
    {
        TAction errs;
        if (c.Const().SameSite == ESameSite::None) {
            if (GetOrSetUATraits(args.Descr).SameSiteNoneSupport) {
                if (!c.Const().Secure) {
                    errs.Reasons.Set(EResponseCookieReason::NotSecure);
                    if (!args.DryRun) {
                        c.Mutable().Secure = true;
                    }
                }
            } else {
                errs.Reasons.Set(EResponseCookieReason::BadSameSite);
                if (!args.DryRun) {
                    c.Mutable().SameSite = ESameSite::Undefined;
                }
            }
        } else {
            if (GetOrSetUATraits(args.Descr).SameSiteNoneSupport) {
                errs.Reasons.Set(EResponseCookieReason::BadSameSite);
                if (!args.DryRun) {
                    auto& mc = c.Mutable();
                    mc.SameSite = ESameSite::None;
                    mc.Secure = true;
                }
            } else if (c.Const().SameSite != ESameSite::Undefined) {
                errs.Reasons.Set(EResponseCookieReason::BadSameSite);
                if (!args.DryRun) {
                    c.Mutable().SameSite = ESameSite::Undefined;
                }
            }
        }
        if (errs.Reasons) {
            return errs;
        }
        return Nothing();
    }
}
