#pragma once
#include <util/datetime/base.h>
#include <library/cpp/logger/global/global.h>

template <bool Additive = false>
class TTimeGuardImpl {
private:
    ui64* Storage = nullptr;
    TDuration* StorageDuration = nullptr;
    const TInstant Start;
    const TString Comment;
public:
    TTimeGuardImpl(ui64& storageLink)
        : Storage(&storageLink)
        , Start(Now()) {

    }

    TTimeGuardImpl(const TString& comment)
        : Start(Now())
        , Comment(comment)
    {
        INFO_LOG << Comment << ": START" << Endl;
    }

    TTimeGuardImpl(TDuration& storageLink)
        : StorageDuration(&storageLink)
        , Start(Now())
    {

    }

    TTimeGuardImpl()
        : Start(Now())
    {
        CHECK_WITH_LOG(!Additive);
    }

    ui64 Release() {
        if (StorageDuration) {
            if (Additive) {
                *StorageDuration += Now() - Start;
            } else {
                *StorageDuration = Now() - Start;
            }
            return StorageDuration->MicroSeconds();
        } else if (Storage) {
            if (Additive) {
                *Storage += (Now() - Start).MicroSeconds();
            } else {
                *Storage = (Now() - Start).MicroSeconds();
            }
            return *Storage;
        } else {
            TDuration result = Now() - Start;
            INFO_LOG << Comment << ": FINISH(" << result.ToString() << ")" << Endl;
            return result.MicroSeconds();
        }
    }

    ~TTimeGuardImpl() {
        Release();
    }
};

using TTimeGuard = TTimeGuardImpl<false>;
using TTimeGuardAdditive = TTimeGuardImpl<true>;
