// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
//--------------------------------------------------------------------------------------
// Telemetry.h
//
// Telemetry definition common functions.
//
// Based on GameTelemetry module provided by Advanced Technology Group (ATG)
// Copyright (C) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------

#pragma once

#include "CoreMinimal.h"
#include "Misc/Variant.h"

#include "TelemetryInterfaces.h"
#include "TelemetryBuilder.h"
#include "TelemetryManager.h"

SIMPLYGONTELEMETRY_API DECLARE_LOG_CATEGORY_EXTERN(LogTelemetry, Log, All);

// Format a semantic version string given the provided values
FORCEINLINE FString FormatVersion(int32 Major, int32 Minor, int32 Patch) { return FString::Printf(TEXT("%d.%d.%d"), Major, Minor, Patch); }


// Common usage library for telemetry
class SIMPLYGONTELEMETRY_API FTelemetry
{
public:
    /**
        Creates an empty telemetry builder
    */
    FORCEINLINE static FTelemetryBuilder Create() { return FTelemetryBuilder(); }

    /**
        Creates a telemetry builder
        @param Properties: Initial properties to set in this event
    */
    FORCEINLINE static FTelemetryBuilder Create(FTelemetryPropertiesInitializer InitialProperties = {})
    {
        FTelemetryBuilder Evt(InitialProperties);
        return Evt;
    }

    /**
        Creates a telemetry builder
        @param Properties: Initial properties to set in this event
    */
    FORCEINLINE static FTelemetryBuilder Create(FTelemetryProperties &&Properties)
    {
        FTelemetryBuilder Evt(MoveTemp(Properties));
        return Evt;
    }

    /**
        Records an event and places it in the buffer to be sent
        @param Name: Event name
        @param Category: Category
        @param Version: Semantic version of this event
        @param Properties: Properties to set in this event
    */
    FORCEINLINE static void Record(const FString &Name, const FString &Category, const FTelemetryBuilder &Properties)
    {
        FTelemetryManager::Get().Record(Name, Category, FTelemetryBuilder(Properties));
    }

    /**
        Records an event and places it in the buffer to be sent
        @param Name: Event name
        @param Category: Category
        @param Version: Semantic version of this event
        @param Properties: Properties to set in this event
    */
    FORCEINLINE static void Record(const FString &Name, const FString &Category, const FTelemetryProperties &Properties)
    { 
        FTelemetryManager::Get().Record(Name, Category, FTelemetryBuilder(Properties));
    }

    /**
        Records an event and places it in the buffer to be sent
        @param Name: Event name
        @param Category: Category
        @param Version: Semantic version of this event
        @param InitialProperties: Initializer list of properties to set in this event
    */
    FORCEINLINE static void Record(const FString &Name, const FString &Category, FTelemetryPropertiesInitializer InitialProperties = {})
    {
        FTelemetryManager::Get().Record(Name, Category, Create(InitialProperties));
    }

// Helper functions for consistently formatting special properties
public:
    // Name of the event
    FORCEINLINE static FTelemetryProperty EventName(const FString &Name) { return FTelemetryProperty(TEXT("ue4_evt_name"), Name); }

    // Category for an event - Useful for grouping events of a similary type
    FORCEINLINE static FTelemetryProperty Category(const FString &Value) { return FTelemetryProperty(TEXT("ue4_cat"), Value); }

    // Timestamp of the event using the client's clock by default
    FORCEINLINE static FTelemetryProperty ClientTimestamp(const FDateTime &Value = FDateTime::UtcNow()) { return FTelemetryProperty("ue4_client_ts", Value); }

    // Unique client id for the device playing the game
    // Typically set in the Common Properties
    FORCEINLINE static FTelemetryProperty ClientId(const FString &Value) { return FTelemetryProperty(TEXT("ue4_client_id"), Value); }

    // Unique session id for the current play session
    FORCEINLINE static FTelemetryProperty SessionId(const FString &Value) { return FTelemetryProperty(TEXT("ue4_session_id"), Value); }

    // Semantic version of the telemetry event
    // Use this to help data pipelines understand how to process the event after ingestion
    FORCEINLINE static FTelemetryProperty Version(const FString &Value) { return FTelemetryProperty(TEXT("ue4_tver"), Value); }

    // Semantic version of a component of the telemetry - Typically used by Telemetry Providers
    // Use this to help data pipelines understand how to process the event after ingestion
    FORCEINLINE static FTelemetryProperty Version(const FString &SubEntity, const FString &Value) { return FTelemetryProperty(TEXT("ue4_tver_") + SubEntity, Value); }

    // A value that represents a percentage float between 0 and 100
    FORCEINLINE static FTelemetryProperty Percentage(const FString &SubEntity, const float &Value)
    {
        check(Value >= 0.f && Value <= 100.f);
        return FTelemetryProperty(TEXT("ue4_pct_") + SubEntity, Value);
    }

    // A float value
    FORCEINLINE static FTelemetryProperty Value(const FString &SubEntity, const float &Value) { return FTelemetryProperty(TEXT("ue4_val_") + SubEntity, Value);	}

    // Generic telemetry property maker
    template<typename T>
    FORCEINLINE static FTelemetryProperty Prop(const FString &Name, const T &Value) { return FTelemetryProperty(TEXT("ue4_") + Name, Value); }


public:
    // Debug utility function for outputting telemetry to a string for printing
    static FString DumpJson(FTelemetryProperties Properties);
};


namespace Simplygon {
	namespace Telemetry {
		namespace Constants {

			static FString LevelEditor(TEXT("LevelEditor"));
			static FString Commandlet(TEXT("Commandlet"));
			static FString ContextMenu(TEXT("ContextMenu"));
			static FString ContentBrowser(TEXT("ContentBrowser"));
			static FString StaticMeshEditor(TEXT("StaticMeshEditor"));
			static FString Persona(TEXT("PersonaEditor"));
			static FString Toolbar(TEXT("Toolbar"));
			static FString Editor(TEXT("Editor"));
			static FString Factory(TEXT("Factory"));
			static FString Visualizer(TEXT("Visualizer"));

			static FString LODRecipe(TEXT("LODRecipe"));
			static FString NavMeshVis(TEXT("NavmeshVisualizer"));
			static FString ClippingPlanesVis(TEXT("ClippingPlanesVisualizer"));

			static FString Standin(TEXT("Standin"));
			static FString StandinOutliner(TEXT("StandinOutliner"));
			static FString StandinActor(TEXT("StandinActor"));
		}
}
}

namespace SGTC = Simplygon::Telemetry::Constants;