#include "policy_errors.h"

#include <balancer/kernel/cookie/domain/domain.h>
#include <balancer/kernel/http/parser/http.h>

namespace NModCookiePolicy {
    TStringBuf ToStringBuf(ECookieAction a) noexcept {
        switch (a) {
        case ECookieAction::Fix: return "Fix"sv;
        case ECookieAction::Drop: return "Drop"sv;
        case ECookieAction::Add: return "Add"sv;
        }
    }

    TStringBuf ToStringBuf(EPolicyResult res) noexcept {
        switch (res) {
        case EPolicyResult::Off: return "off"sv;
        case EPolicyResult::Skip: return "skip"sv;
        case EPolicyResult::Pass: return "pass"sv;
        case EPolicyResult::FailDryRun: return "fail+dryRun"sv;
        case EPolicyResult::FailFix: return "fail+fix"sv;
        }
    }

    namespace {
        template <class TErrEnum>
        size_t PrintSz(const TVector<TCookieAction<TErrEnum>>& results) noexcept {
            size_t sz = 0;
            for (auto&& res : results) {
                sz += 1 + res.Info.size() + 1 + ToStringBuf(res.Action).size() + 1 + 2 + 1 + res.Reasons.PrintSz();
            }
            return sz;
        }

        template <class TErrEnum>
        void Print(TString& log, const TVector<TCookieAction<TErrEnum>>& actions) noexcept {
            for (auto&& act : actions) {
                log.append(' ').append(act.Info).append('=').append(ToStringBuf(act.Action)).append(':');
                char buf[32] = {};
                log.append(TStringBuf(buf, IntToString<10>(act.Count, buf, sizeof(buf)))).append('!');
                act.Reasons.Print(log);
            }
        }

        template <class TErrEnum>
        TString DoLogPolicyResult(
            TStringBuf prefix, TStringBuf uuid, bool dryRun, const TVector<TCookieAction<TErrEnum>>& actions) noexcept
        {
            const auto resStr = ToStringBuf(dryRun ? EPolicyResult::FailDryRun : EPolicyResult::FailFix);
            size_t sz = prefix.size() + uuid.size() + 1 + resStr.size() + PrintSz(actions) + 1;
            TString log(Reserve(sz));
            log.append(prefix).append(uuid).append(' ').append(resStr);
            Print(log, actions);
            log.append(']');
            return log;
        }
    }

    TString LogPolicyResult(TStringBuf uuid, bool dryRun, const TRequestCookieActions& actions) noexcept {
        return DoLogPolicyResult(TStringBuf(" [cpol-req u:"), uuid, dryRun, actions);
    }

    TString LogPolicyResult(TStringBuf uuid, bool dryRun, const TResponseCookieActions& actions) noexcept {
        return DoLogPolicyResult(TStringBuf(" [cpol u:"), uuid, dryRun, actions);
    }

    TString LogParserResult(TStringBuf uuid, bool dryRun, const TSetCookieParserErrors& actions) noexcept {
        return DoLogPolicyResult(TStringBuf(" [cpol u:"), uuid, dryRun, actions);
    }

    void MaybeReportCookieProblems(const TRequest& req, TResponse& resp, const TString& logs) noexcept {
        if (req.Headers().GetFirstValue("X-Yandex-Show-Cookie-Problems") == "1" &&
            req.Headers().GetFirstValue("X-Yandex-Internal-Request") == "1") {
            resp.Headers().Add("X-Yandex-Cookie-Problems", logs);
        }
    }

}
