#include "common.h"
#include "access_log.h"

#include <saas/searchproxy/common/cgi.h>
#include <saas/searchproxy/search_meta/extendedcontext.h>
#include <search/request/data/reqdata.h>
#include <search/session/reqenv.h>

#include <kernel/search_daemon_iface/cntintrf.h>
#include <library/cpp/http/misc/httpreqdata.h>
#include <library/cpp/cgiparam/cgiparam.h>

using namespace NSearchProxy::NLogging;

namespace {
    template <class TContext>
    void LogInfoImpl(ui32 id, const TContext& context) {
        if (!TLoggerOperator<TInfoLog>::Usage())
            return;
        const TSearchRequestData& rd = context.GetRequestData();
        NUtil::TTSKVRecord record(TLoggerOperator<TInfoLog>::Get()->GetName());
        TReqEnv* reqEnv = context.GetReqEnv();
        const TCgiParameters* cgi = nullptr;
        if (reqEnv) {
            cgi = &reqEnv->CgiParam;
        } else {
            cgi = &rd.CgiParam;
        }
        TInstant requestBeginTime = TInstant::MicroSeconds(rd.RequestBeginTime());
        record.Add(IdLable, id);
        record.Add(StatTimestampLable, requestBeginTime.Seconds());
        record.Add(HrTimeLable, Now().ToString());
        InsertIncomingInfo(record, rd);
        InsertQueryInfo(record, *cgi, rd);
        record.Add(HttpStatusLable, context.HttpStatus());
        record.Add(ReplyTimeLable, GetRequestDuration(rd));
        record.ForceAdd(NotFetchedLable, context.NotFetched());
        record.ForceAdd(IsCompleteLable, context.AnswerIsComplete());
        record.ForceAdd(DocCountLable, context.GetTotalDocsCount());
        record.ForceAdd(ReportKbSizeLable, context.GetReportByteSize() / 1000);
        record.ForceAdd(CacheHitLable, reqEnv ? reqEnv->CacheHit() : 0);
        record.Add(MetaServiceLable, cgi->Get(NSearchProxyCgi::metaservice));
        record.ForceAdd(TimeoutedLable, context.Timeouted());
        record.ForceAdd(RequestSubtypeLable, int(context.RequestType()));
        record.Add(ReportTimeLable, GetReportDuration(context));
        record.Add(WaitTimeLable, GetWaitInQueueDuration(context));

        if (reqEnv) {
            const size_t failedSourceCount = reqEnv->NotRespondedSourcesCount();
            record.Add(ErrorLable, TString(reqEnv->ErrorText()));
            record.Add(FailedSourceCountLable, failedSourceCount);
            for (size_t i = 0; i < failedSourceCount; ++i) {
                record.Add(FailedSourceNameLable, reqEnv->NotRespondedSourceName(i));
            }
        }

        record.Add("tvm_status", rd.CgiParam.Get("tvm_auth_status"));

        TLoggerOperator<TInfoLog>::Log() << record.ToString() << Endl;
    }
}

void TInfoLog::Log(ui32 id, const TExtendedSearchContext& context) {
    ::LogInfoImpl<TExtendedSearchContext>(id, context);
}

void TInfoLog::Log(ui32 id, const TExtendedReplyContext& context) {
    ::LogInfoImpl<TExtendedReplyContext>(id, context);
}
