#include <balancer/production/x/h2_log_processor/lib/get_error_sessions.h>
#include <balancer/production/x/h2_log_processor/lib/file_manager.h>
#include <balancer/production/x/h2_log_processor/lib/run_all.h>
#include <balancer/production/x/h2_log_processor/lib/summarize_streams.h>
#include <balancer/production/x/h2_log_processor/lib/split_by_pri_succ.h>
#include <balancer/production/x/h2_log_processor/lib/summarize_sessions.h>
#include <balancer/production/x/h2_log_processor/lib/dump_raw_header_blocks.h>
#include <balancer/production/x/h2_log_processor/lib/parse_raw_header_blocks.h>

#include <library/cpp/getopt/modchooser.h>
#include <library/cpp/getopt/last_getopt.h>
#include <util/stream/file.h>
#include <util/stream/zlib.h>

namespace {

    struct TPresets {
        NH2Log::TFileManagerOpts FileOpts;
        NLastGetopt::TOpts Opts;
        bool UseWorkspace = false;

        TPresets() = default;
    };


    NH2Log::TFileManager InitFileManager(TPresets& presets, int argc, const char** argv) {
        presets.Opts.AddCharOption('w', "workspace").SetFlag(&presets.UseWorkspace);
        presets.Opts.SetFreeArgTitle(0, "in_log_name");
        presets.Opts.SetFreeArgTitle(1, "out_suff");
        presets.Opts.SetFreeArgsMin(1);
        presets.Opts.SetFreeArgsMax(2);
        NLastGetopt::TOptsParseResult res(&presets.Opts, argc, argv);
        if (res.GetFreeArgCount() > 1) {
            presets.FileOpts.OutputSuffix = res.GetFreeArgs()[1];
        }
        TString input = res.GetFreeArgs()[0];
        if (presets.UseWorkspace) {
            input = NH2Log::ChDirToWorkspace(input);
        }
        return NH2Log::TFileManager(input, presets.FileOpts);
    }


    int DoGetErrSess(int argc, const char** argv) {
        TPresets presets;
        auto manager = InitFileManager(presets, argc, argv);
        NH2Log::GetErrorSessions(manager);
        return 0;
    }

    int DoSplitByPriSucc(int argc, const char** argv) {
        TPresets presets;
        auto manager = InitFileManager(presets, argc, argv);
        NH2Log::SplitByPriSucc(manager);
        return 0;
    }

    int DoSummarizeErrorStreams(int argc, const char** argv) {
        TPresets presets;
        auto manager = InitFileManager(presets, argc, argv);
        NH2Log::SummarizeErrorStreams(manager);
        return 0;
    }

    int DoSummarizeErrorSessions(int argc, const char** argv) {
        TPresets presets;
        TVector<NH2Log::ESessionSummary> summarizers;
        presets.Opts.AddLongOption('d', "details").AppendTo(&summarizers).Required();
        auto manager = InitFileManager(presets, argc, argv);
        NH2Log::SummarizeSessions(manager, summarizers);
        return 0;
    }

    int DoSummarizeSlowStreams(int argc, const char** argv) {
        TDuration minDuration;
        bool humanReadable = false;
        TPresets presets;
        presets.Opts.AddLongOption('m', "min-duration").StoreResult(&minDuration).Required();
        presets.Opts.AddLongOption('h', "human").SetFlag(&humanReadable).Optional();
        auto manager = InitFileManager(presets, argc, argv);
        NH2Log::SummarizeSlowStreams(manager, minDuration, humanReadable);
        return 0;
    }

    int DoSummarizeSlowStreamSends(int argc, const char** argv) {
        TDuration minDuration;
        bool humanReadable = false;
        TPresets presets;
        presets.Opts.AddLongOption('m', "min-duration").StoreResult(&minDuration).Required();
        presets.Opts.AddLongOption('h', "human").SetFlag(&humanReadable).Optional();
        auto manager = InitFileManager(presets, argc, argv);
        NH2Log::SummarizeSlowStreamSends(manager, minDuration, humanReadable);
        return 0;
    }

    int DoDumpRawClientHeaderBlocks(int argc, const char** argv) {
        TPresets presets;
        auto manager = InitFileManager(presets, argc, argv);
        NH2Log::DumpRawClientHeaderBlocks(manager);
        return 0;
    }

    int DoParseRawClientHeaderBlocks(int argc, const char** argv) {
        TPresets presets;
        auto manager = InitFileManager(presets, argc, argv);
        NH2Log::ParseRawClientHeaderBlocks(manager);
        return 0;
    }

    int DoRunAll(int argc, const char** argv) {
        TPresets presets;
        presets.UseWorkspace = true;
        presets.Opts.AddLongOption('k', "keep-existing").NoArgument().SetFlag(&presets.FileOpts.KeepExisting);
        auto manager = InitFileManager(presets, argc, argv);
        NH2Log::RunAll(manager);
        return 0;
    }
}

int main(int argc, const char** argv) {
    TModChooser modChooser;
    modChooser.AddMode("get_err_sess", DoGetErrSess,
                       "Extract h2 sessions containing errors");
    modChooser.AddMode("split_by_pri_succ", DoSplitByPriSucc,
                       "Classify h2 sessions as PRI success and PRI fail");
    modChooser.AddMode("summarize_error_streams", DoSummarizeErrorStreams,
                       "Summarize streams with errors in h2 sessions");
    modChooser.AddMode("summarize_error_sessions", DoSummarizeErrorSessions,
                       "Summarize h2 sessions with errors");
    modChooser.AddMode("summarize_slow_streams", DoSummarizeSlowStreams,
                       "Summarize slow stream timings");
    modChooser.AddMode("summarize_slow_stream_sends", DoSummarizeSlowStreamSends,
                       "Summarize slow stream send timings");
    modChooser.AddMode("dump_raw_client_header_blocks", DoDumpRawClientHeaderBlocks,
                       "Dump raw client header blocks");
    modChooser.AddMode("parse_raw_client_header_blocks", DoParseRawClientHeaderBlocks,
                       "Dump parsed client headers");
    modChooser.AddMode("run_all", DoRunAll, "Run all analytics");
    return modChooser.Run(argc, argv);
}
