#include "aux_utils.h"
#include "dump_raw_header_blocks.h"
#include "get_error_sessions.h"
#include "run_all.h"
#include "split_by_pri_succ.h"
#include "summarize_sessions.h"
#include "summarize_streams.h"

namespace NH2Log {

    namespace {
        struct TErrorFile {
            TError Error;
            TString FileName;
            bool PriSuccess = true;

            TErrorFile(const TError& error, const TString& fileName, bool priSuccess = true)
                : Error(error)
                , FileName(fileName)
                , PriSuccess(priSuccess)
            {}
        };

        static const auto SendGoAway = std::make_tuple(EErrorSource::Send, EErrorType::GOAWAY);
        static const auto RecvGoAway = std::make_tuple(EErrorSource::Recv, EErrorType::GOAWAY);
    }

    void RunAll(TFileManager& manager) {
        Y_H2_LOG_FUNC(manager);

        if (manager.HasDoneTag(__func__)) {
            Y_H2_LOG_EVENT << "Found done tag: " << manager.GetDoneTag(__func__) << Endl;
            return;
        }

        TVector<TErrorFile> errorFiles;

        {
            for (const auto& session : GetErrorSessions(manager)) {
                if (session.Code == "INTERNAL_ERROR" && session.AsSourceType() == SendGoAway) {
                    auto childManager = manager.CreateChildManager(GetErrorSessionFileName(session));
                    for (auto subSession : SplitByPriSucc(childManager)) {
                        errorFiles.emplace_back(session, subSession.FileName, subSession.Success);
                    }
                } else {
                    errorFiles.emplace_back(session, GetErrorSessionFileName(session));
                }
            }
        }

        for (const auto& errorFile : errorFiles) {
            auto childManager = manager.CreateChildManager(errorFile.FileName);
            if (errorFile.Error.AsSourceType() == RecvGoAway) {
                SummarizeSessions(
                    childManager,
                    {
                        ESessionSummary::UserAgent,
                        ESessionSummary::RecvGoAway,
                        ESessionSummary::StreamsStats,
                    }
                );
            } else if (errorFile.Error.Type == EErrorType::GOAWAY){
                SummarizeSessions(
                    childManager,
                    {
                        ESessionSummary::UserAgent,
                        ESessionSummary::FirstConnException,
                        ESessionSummary::FirstConnCatch,
                        ESessionSummary::FinalConnCatch,
                        ESessionSummary::StreamsStats,
                    }
                );

                if (errorFile.Error.Code == "COMPRESSION_ERROR") {
                    DumpRawClientHeaderBlocks(childManager);
                }
            } else {
                SummarizeSessions(
                    childManager,
                    {
                        ESessionSummary::UserAgent,
                        ESessionSummary::StreamsStats,
                    }
                );
                SummarizeErrorStreams(childManager);
            }
        }

        manager.SetDoneTag(__func__);
    }
}
