/*
 * Tracy Unity Plugin - Simplified Implementation
 * 
 * This is a simplified Tracy Unity Plugin implementation
 * demonstrating how to integrate Tracy into Unity Native Plugin
 * 
 * Build instructions:
 * Windows: Use CMake (see CMakeLists.txt)
 * macOS:   Use CMake (see CMakeLists.txt)
 * Linux:   Use CMake (see CMakeLists.txt)
 */

#pragma warning(disable:4100)

#include "tracy/Tracy.hpp"
#include <string>
#include <cstring>
#include <map>
#include <stack>

// Platform specific export definition
#if defined(_WIN32) || defined(_WIN64)
    #define UNITY_PLUGIN_EXPORT __declspec(dllexport)
#elif defined(__APPLE__) || defined(__linux__)
    #define UNITY_PLUGIN_EXPORT __attribute__((visibility("default")))
#else
    #define UNITY_PLUGIN_EXPORT
#endif

std::map<std::string, tracy::SourceLocationData> sourceLocationCache;
std::map<std::string, std::string> zoneFunctionNameCache;
std::map<std::string, std::string> zoneFilePathCache;
std::map<std::string, std::stack<tracy::ScopedZone*>> zoneStackCache;

// C export functions (Unity requires C linkage)
extern "C"
{
    /**
     * Initialize Tracy
     * Unity C# call: [DllImport] private static extern void TracyInit();
     */
    UNITY_PLUGIN_EXPORT void TracyInit()
    {
        // Tracy initializes automatically, additional initialization logic can be added here
    }

    /**
     * Shutdown Tracy
     * Unity C# call: [DllImport] private static extern void TracyShutdown();
     */
    UNITY_PLUGIN_EXPORT void TracyShutdown()
    {

    }

    /**
     * Mark frame boundary
     * Unity C# call: [DllImport] private static extern void TracyFrameMark();
     */
    UNITY_PLUGIN_EXPORT void TracyFrameMark()
    {
        FrameMark;
    }

    /**
     * Plot value
     * Unity C# call: [DllImport] private static extern void TracyPlotValue(string name, double value);
     */
    UNITY_PLUGIN_EXPORT void TracyPlotValue(const char* name, double value)
    {
        if (name != nullptr)
        {
            TracyPlot(name, value);
        }
    }

    /**
     * Send message
     * Unity C# call: [DllImport] private static extern void TracySendMessage(string message);
     */
    UNITY_PLUGIN_EXPORT void TracySendMessage(const char* message)
    {
        if (message != nullptr)
        {
            TracyMessage(message, std::strlen(message));
        }
    }

    /**
     * Set thread name
     * Unity C# call: [DllImport] private static extern void TracySetThreadName(string name);
     */
    UNITY_PLUGIN_EXPORT void TracySetThreadName(const char* name)
    {
        if (name != nullptr)
        {
            tracy::SetThreadName(name);
        }
    }

    /**
     * Unity plugin lifecycle function - called on load
     */
    UNITY_PLUGIN_EXPORT void UnityPluginLoad()
    {
        // Optional: perform initialization when plugin loads
    }

    /**
     * Unity plugin lifecycle function - called on unload
     */
    UNITY_PLUGIN_EXPORT void UnityPluginUnload()
    {
        // Optional: perform cleanup when plugin unloads
        TracyShutdown();
    }

    UNITY_PLUGIN_EXPORT void TracyZoneScopedBegin(
        const char* name,
        const char* functionName,
        const char* filePath,
		int lineNumber
    )
    {
        std::string nameStr(name);
        auto iter = sourceLocationCache.find(nameStr);
        if (iter == sourceLocationCache.end())
        {
            zoneFunctionNameCache[nameStr] = functionName;
			zoneFilePathCache[nameStr] = filePath;
            iter = sourceLocationCache.insert(sourceLocationCache.end(), std::make_pair(nameStr, tracy::SourceLocationData{}));
            iter->second.name = iter->first.c_str();
            iter->second.function = zoneFunctionNameCache[nameStr].c_str();
            iter->second.file = zoneFilePathCache[nameStr].c_str();
            iter->second.line = static_cast<uint32_t>(lineNumber);
            iter->second.color = 0;
        }
        zoneStackCache[nameStr].push(new tracy::ScopedZone(&iter->second, 0, true));
    }

    UNITY_PLUGIN_EXPORT void TracyZoneScopedEnd(const char* name)
    {
        delete zoneStackCache[name].top();
        zoneStackCache[name].pop();
    }

} // extern "C"
