#include "rty_access.h"
#include <saas/rtyserver/unistat_signals/signals.h>

#include "escaping.h"

namespace NRtyAccess {
    inline TStringBuf CutQuery(const TStringBuf &query) {
        return TStringBuf(query.data(), Min<size_t>(query.size(), 120000));
    }

    constexpr TDuration::TValue ToMilliSeconds(TDuration duration) {
        return (duration.MicroSeconds() + 500) / 1000;
    }

    NEscaper::TEscaper LoadlogQueryEscaper(TStringBuf str) {
        NEscaper::TEscaper escaper(str);
        escaper.AddMapping(';', "%3B");
        escaper.AddMapping('\0', "%00");
        escaper.AddMapping('\n', "%0A");
        escaper.AddMapping('\t', "%09");
        escaper.AddMapping('\r', "$0D");
        escaper.AddMapping('\\', "%5C");
        return escaper;
    }
}

void TRTYAccessLog::LogIncoming(ui64 id, ui32 count, const TStringBuf address, const TStringBuf query) {
    if (!TLoggerOperator<TRTYAccessLog>::Usage() || TLoggerOperator<TRTYAccessLog>::Log().IsNullLog())
        return;

    auto cut_query = NRtyAccess::CutQuery(query);

    TLoggerOperator<TRTYAccessLog>::Log() << TLOG_INFO << "time=" << NLoggingImpl::GetLocalTimeS()
        << ";ip=" << address
        << ";id=" << id
        << ";num=" << count
        << ";size=" << query.size()
        << ";cut=" << (cut_query.size() < query.size())
        << ";query=" << NRtyAccess::LoadlogQueryEscaper(query) << Endl;
}

void TRTYAccessLog::LogSearch(ui64 id, TDuration full, TDuration process, bool result, ui32 totalCount, ui32 reportCount, ui64 byteSize, float cacheHit, ui32 unanswerCnt, ERequestType requestType, ui32 fastCacheHit, bool failOnZero, i32 answerIsComplete, TStringBuf searchErrors) {
    const auto fullMs = NRtyAccess::ToMilliSeconds(full);
    const auto processMs = NRtyAccess::ToMilliSeconds(process);
    NRTYServer::TUnistatRecordContext ctx(requestType, fullMs, processMs, result);
    ctx.ReportByteSize = byteSize;
    ctx.CacheHit = cacheHit;
    ctx.TotalDocsCount = totalCount;
    ctx.ReportDocsCount = reportCount;
    ctx.CountUnanswered = unanswerCnt;
    ctx.AnswerIsComplete = answerIsComplete;
    ctx.FastCacheHit = fastCacheHit;
    ctx.FailOnZero = failOnZero;
    TSaasRTYServerSignals::DoUnistatRecordSearch(ctx);

    if (!TLoggerOperator<TRTYAccessLog>::Usage() || TLoggerOperator<TRTYAccessLog>::Log().IsNullLog())
        return;

    TLoggerOperator<TRTYAccessLog>::Log() << TLOG_INFO << "time=" << NLoggingImpl::GetLocalTimeS()
        << ";action=search"
        << ";id=" << id
        << ";duration=" << fullMs
        << ";process=" << processMs
        << ";result=" << result
        << ";count_docs=" << totalCount
        << ";report_docs=" << reportCount
        << ";report_kb=" << (byteSize / 1024)
        << ";type=" << int(requestType)
        << ";cachehit=" << cacheHit
        << ";fastCacheHit=" << fastCacheHit
        << ";unanswers=" << unanswerCnt
        << ";answer_is_complete=" << answerIsComplete
        << ";search_errors=" << NRtyAccess::LoadlogQueryEscaper(searchErrors)
        << ";fail_on_zero=" << failOnZero << Endl;
}

void TRTYAccessLog::LogFetch(ui64 id, TDuration full, TDuration process, bool result) {
    if (!TLoggerOperator<TRTYAccessLog>::Usage() || TLoggerOperator<TRTYAccessLog>::Log().IsNullLog())
        return;

    TLoggerOperator<TRTYAccessLog>::Log() << TLOG_INFO << "time=" << NLoggingImpl::GetLocalTimeS()
        << ";action=fetch"
        << ";id=" << id
        << ";duration=" << NRtyAccess::ToMilliSeconds(full)
        << ";process=" << NRtyAccess::ToMilliSeconds(process)
        << ";result=" << result << Endl;
}

void TRTYAccessLog::LogError(ui64 id, TDuration full, const TStringBuf error) {
    if (!TLoggerOperator<TRTYAccessLog>::Usage() || TLoggerOperator<TRTYAccessLog>::Log().IsNullLog())
        return;

    TLoggerOperator<TRTYAccessLog>::Log() << TLOG_ERR << "time=" << NLoggingImpl::GetLocalTimeS()
        << ";action=error"
        << ";id=" << id
        << ";duration=" << NRtyAccess::ToMilliSeconds(full)
        << ";message=" << error << Endl;
}

void TRTYAccessLog::LogError(const TStringBuf error) {
    TLoggerOperator<TRTYAccessLog>::Log() << TLOG_ERR << "time=" << NLoggingImpl::GetLocalTimeS()
        << ";action=error"
        << ";message=" << error << Endl;
}
