#pragma once
#include <string>
#include <vector>
#include <chrono>
#include "EngineConfig.h"


#include <json.hpp>
using json = nlohmann::json;


struct ProfileNode {
    std::string name;
    double startMs = 0.0;
    double durationMs = 0.0;
    double visualStartMs = 0.0;
    double visualDurationMs = 0.0;
    std::vector<ProfileNode> children;

    ProfileNode() = default;
    ProfileNode(const std::string& n, double start) : name(n), startMs(start) {
        children.reserve(8);
    }
};

class HierarchicalProfiler {
public:
    void BeginFrame();
    void EndFrame();

    void BeginSection(const std::string& name);
    void EndSection();

    void BeginEngineSection(const std::string& name);
    void EndEngineSection();

    void BeginDeepSection(const std::string& name);
    void EndDeepSection();

    const std::vector<ProfileNode>& GetFrames() const;
    const ProfileNode* GetLatestFrame() const;

private:
    using Clock = std::chrono::high_resolution_clock;
    Clock::time_point startTime;
    std::vector<Clock::time_point> sectionStartTimes;
    std::vector<ProfileNode*> currentStack;
    ProfileNode root{"Frame", 0.0};

    std::vector<ProfileNode> frameHistory;
    static constexpr size_t maxFrames = 30;

    size_t ProfilesLastFrame = 128;
};

json SerializeProfileNode(const ProfileNode& node);

extern HierarchicalProfiler profiler;

struct ScopedProfile {
    ScopedProfile(const std::string& name) {
        if (g_engineConfig.settings.profile_enabled)
            profiler.BeginSection(name);
    }
    ~ScopedProfile() {
        if (g_engineConfig.settings.profile_enabled)
            profiler.EndSection();
    }
};

struct ScopedEngineProfile {
    ScopedEngineProfile(const std::string& name) {
        if (g_engineConfig.settings.profile_enabled && g_engineConfig.settings.profile_editor)
            profiler.BeginSection(name);
    }
    ~ScopedEngineProfile() {
        if (g_engineConfig.settings.profile_enabled && g_engineConfig.settings.profile_editor)
            profiler.EndSection();
    }
};

#ifndef DISABLE_DEEP_PROFILING
struct ScopedDeepProfile {
    ScopedDeepProfile(const std::string& name) {
        if (g_engineConfig.settings.profile_deep)
            profiler.BeginDeepSection(name);
    }
    ~ScopedDeepProfile() {
        if (g_engineConfig.settings.profile_deep)
            profiler.EndDeepSection();
    }
};
#else
struct ScopedDeepProfile {
    ScopedDeepProfile(const std::string&) {}
    ~ScopedDeepProfile() {}
};
#endif

#define CONCAT_IMPL(a, b) a##b
#define CONCAT(a, b) CONCAT_IMPL(a, b)

#define PROFILE_SCOPE(name) ScopedProfile CONCAT(_prof_, __LINE__)(name)
#define PROFILE_ENGINE_SCOPE(name) ScopedEngineProfile CONCAT(_eprof_, __LINE__)(name)
#define PROFILE_DEEP_SCOPE(name) ScopedDeepProfile CONCAT(_dprof_, __LINE__)(name)
