#pragma once
#include <string>
#include <vector>
#include <unordered_map>
#include <chrono>
namespace OX
{
    class Profiler {
    public:
        static void BeginFrame();
        static void EndFrame();

        static void StartSample(const std::string& name);
        static void EndSample(const std::string& name);

        static const std::vector<std::string>& GetFormattedData();

        struct SavedSample {
            std::string name;
            double totalTime;
            int callCount;
            std::vector<SavedSample> children;
        };

        static const std::vector<SavedSample>& GetSavedTree();

    private:
        struct Sample {
            double totalTime = 0.0;
            int callCount = 0;
            std::vector<std::string> children;
        };

        static inline std::unordered_map<std::string, Sample> s_samples;
        static inline std::unordered_map<std::string, std::chrono::high_resolution_clock::time_point> s_startTimes;
        static inline std::vector<std::string> s_stack;
        static inline std::vector<std::string> s_formatted;
        static inline std::vector<std::string> s_lastFormatted;
        static inline std::vector<SavedSample> s_savedTree;
        static inline std::vector<SavedSample> s_lastSavedTree;
    };

    class ProfileScope {
    public:
        explicit ProfileScope(const std::string& name);
        ~ProfileScope();

    private:
        std::string m_name;
    };


#if defined(_MSC_VER)
#define __FUNC_NAME__ __FUNCSIG__
#else
#define __FUNC_NAME__ __PRETTY_FUNCTION__
#endif

#if defined(_DEBUG) || defined(DEBUG)

#define OX_PROFILE_FUNCTION() ProfileScope __profile_scope__##__LINE__(__FUNC_NAME__)
#define OX_PROFILE_LABEL(name) ProfileScope __profile_scope__##__LINE__(name)

#else

#define OX_PROFILE_FUNCTION()
#define OX_PROFILE_LABEL(name)

#endif
}
