// Copyright 2025, Algoryx Simulation AB.

#pragma once

#include "CoreMinimal.h"
#include "Stats/Stats.h"

// There are some long names here that I find easier to keep track of when aligned over long lines
// even when they go off the end of the window.
//
// clang-format off

// Statistics generated by the plugin itself.
// These are enabled with 'stat AGXUnreal' in the console
DECLARE_STATS_GROUP(TEXT("AGX Unreal"), STATGROUP_AGXUnreal, STATCAT_Advanced);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Step Time"),  STAT_AGXU_StepTime, STATGROUP_AGXUnreal);
DECLARE_DWORD_COUNTER_STAT(TEXT("Num. Steps"), STAT_AGXU_NumSteps, STATGROUP_AGXUnreal);

// Timers read from AGX Dynamics, last step in a frame only. So timer spikes in non-last frames will
// not be visible. Use the FRAME stats to detect those.
// These are enabled with 'stat AGXDynamicsStepTimers' in the console
DECLARE_STATS_GROUP(TEXT("AGX Dynamics Timers Last Step Forward"), STATGROUP_AGXDynamicsStepTimers, STATCAT_Advanced);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Step forward time"),                    STAT_AGXD_SimStepForward_STEP,               STATGROUP_AGXDynamicsStepTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Pre-collide event time"),               STAT_AGXD_SimPreCollide_STEP,                STATGROUP_AGXDynamicsStepTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Collision-detection time"),             STAT_AGXD_SimCollisionDetection_STEP,        STATGROUP_AGXDynamicsStepTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Triggering contact separation events"), STAT_AGXD_SimContactSeparationEvents_STEP,   STATGROUP_AGXDynamicsStepTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Triggering contact events"),            STAT_AGXD_SimContactEvents_STEP,             STATGROUP_AGXDynamicsStepTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Contact reduction"),                    STAT_AGXD_SimContactReduction_STEP,          STATGROUP_AGXDynamicsStepTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Culling contacts"),                     STAT_AGXD_SimCullingContacts_STEP,           STATGROUP_AGXDynamicsStepTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Committing removed contacts"),          STAT_AGXD_SimCommittingRemovedContacts_STEP, STATGROUP_AGXDynamicsStepTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Pre-step event time"),                  STAT_AGXD_SimPreStep_STEP,                   STATGROUP_AGXDynamicsStepTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Dynamics-system time"),                 STAT_AGXD_SimDynamicsSystem_STEP,            STATGROUP_AGXDynamicsStepTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Post-step event time"),                 STAT_AGXD_SimPostStep_STEP,                  STATGROUP_AGXDynamicsStepTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Last-step event time"),                 STAT_AGXD_SimLastStep_STEP,                  STATGROUP_AGXDynamicsStepTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Unaccounted"),                          STAT_AGXD_SimUnaccounted_STEP,               STATGROUP_AGXDynamicsStepTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Update RenderManager"),                 STAT_AGXD_SimUpdateRenderManager_STEP,       STATGROUP_AGXDynamicsStepTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Inter-step time"),                      STAT_AGXD_SimInterStep_STEP,                 STATGROUP_AGXDynamicsStepTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Space: Update time"),                               STAT_AGXD_SpaceUpdate_STEP,                  STATGROUP_AGXDynamicsStepTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Space: Broad-phase time"),                          STAT_AGXD_SpaceBroadPhase_STEP,              STATGROUP_AGXDynamicsStepTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Space: Narrow-phase time"),                         STAT_AGXD_SpaceNarrowPhase_STEP,             STATGROUP_AGXDynamicsStepTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Space: Sync bounds time"),                          STAT_AGXD_SpaceSyncBounds_STEP,              STATGROUP_AGXDynamicsStepTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Space: Sync transforms time"),                      STAT_AGXD_SpaceSyncTransforms_STEP,          STATGROUP_AGXDynamicsStepTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Dynamics System: Update time"),                     STAT_AGXD_DynSysUpdate_STEP,                 STATGROUP_AGXDynamicsStepTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Dynamics System: Solver time"),                     STAT_AGXD_DynSysSolver_STEP,                 STATGROUP_AGXDynamicsStepTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Dynamics System: Sabre: Factoring"),                STAT_AGXD_DynSysSabreFactoring_STEP,         STATGROUP_AGXDynamicsStepTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Dynamics System: Sabre: Solve"),                    STAT_AGXD_DynSysSabreSolve_STEP,             STATGROUP_AGXDynamicsStepTimers);

// Timers read from AGX Dynamics accumulated over a frame.
// These are enabled with 'stat AGXDynamicsFrameTimers' in the console
DECLARE_STATS_GROUP(TEXT("AGX Dynamics Timers Entire Frame"), STATGROUP_AGXDynamicsFrameTimers, STATCAT_Advanced);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Step forward time"),                    STAT_AGXD_SimStepForward_FRAME,               STATGROUP_AGXDynamicsFrameTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Pre-collide event time"),               STAT_AGXD_SimPreCollide_FRAME,                STATGROUP_AGXDynamicsFrameTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Collision-detection time"),             STAT_AGXD_SimCollisionDetection_FRAME,        STATGROUP_AGXDynamicsFrameTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Triggering contact separation events"), STAT_AGXD_SimContactSeparationEvents_FRAME,   STATGROUP_AGXDynamicsFrameTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Triggering contact events"),            STAT_AGXD_SimContactEvents_FRAME,             STATGROUP_AGXDynamicsFrameTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Contact reduction"),                    STAT_AGXD_SimContactReduction_FRAME,          STATGROUP_AGXDynamicsFrameTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Culling contacts"),                     STAT_AGXD_SimCullingContacts_FRAME,           STATGROUP_AGXDynamicsFrameTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Committing removed contacts"),          STAT_AGXD_SimCommittingRemovedContacts_FRAME, STATGROUP_AGXDynamicsFrameTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Pre-step event time"),                  STAT_AGXD_SimPreStep_FRAME,                   STATGROUP_AGXDynamicsFrameTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Dynamics-system time"),                 STAT_AGXD_SimDynamicsSystem_FRAME,            STATGROUP_AGXDynamicsFrameTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Post-step event time"),                 STAT_AGXD_SimPostStep_FRAME,                  STATGROUP_AGXDynamicsFrameTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Last-step event time"),                 STAT_AGXD_SimLastStep_FRAME,                  STATGROUP_AGXDynamicsFrameTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Update RenderManager"),                 STAT_AGXD_SimUpdateRenderManager_FRAME,       STATGROUP_AGXDynamicsFrameTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Inter-step time"),                      STAT_AGXD_SimInterStep_FRAME,                 STATGROUP_AGXDynamicsFrameTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Simulation: Unaccounted"),                          STAT_AGXD_SimUnaccounted_FRAME,               STATGROUP_AGXDynamicsFrameTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Space: Update time"),                               STAT_AGXD_SpaceUpdate_FRAME,                  STATGROUP_AGXDynamicsFrameTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Space: Broad-phase time"),                          STAT_AGXD_SpaceBroadPhase_FRAME,              STATGROUP_AGXDynamicsFrameTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Space: Narrow-phase time"),                         STAT_AGXD_SpaceNarrowPhase_FRAME,             STATGROUP_AGXDynamicsFrameTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Space: Sync bounds time"),                          STAT_AGXD_SpaceSyncBounds_FRAME,              STATGROUP_AGXDynamicsFrameTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Space: Sync transforms time"),                      STAT_AGXD_SpaceSyncTransforms_FRAME,          STATGROUP_AGXDynamicsFrameTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Dynamics System: Update time"),                     STAT_AGXD_DynSysUpdate_FRAME,                 STATGROUP_AGXDynamicsFrameTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Dynamics System: Solver time"),                     STAT_AGXD_DynSysSolver_FRAME,                 STATGROUP_AGXDynamicsFrameTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Dynamics System: Sabre: Factoring"),                STAT_AGXD_DynSysSabreFactoring_FRAME,         STATGROUP_AGXDynamicsFrameTimers);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Dynamics System: Sabre: Solve"),                    STAT_AGXD_DynSysSabreSolve_FRAME,             STATGROUP_AGXDynamicsFrameTimers);

// Counters read from AGX Dynamics. These are only reported for the last Step Forward in a frame,
// so if the numbers vary during that frame then only the last frame's number will be reported.
// These are enabled with 'stat AGXDynamicsCounts' in the console
DECLARE_STATS_GROUP(TEXT("AGX Dynamics Counts"), STATGROUP_AGXDynamicsCounts, STATCAT_Advanced);
DECLARE_DWORD_COUNTER_STAT(TEXT("Simulation: Num Particles"),                               STAT_AGXD_SimNumParticles,                           STATGROUP_AGXDynamicsCounts);
DECLARE_DWORD_COUNTER_STAT(TEXT("Simulation: Num Contacts Removed"),                        STAT_AGXD_SimNumContactsRemoved,                     STATGROUP_AGXDynamicsCounts);
DECLARE_DWORD_COUNTER_STAT(TEXT("Simulation: Num Warm Started Particle-Particle Contacts"), STAT_AGXD_SimNumWarmStartedParticleParticleContacts, STATGROUP_AGXDynamicsCounts);
DECLARE_DWORD_COUNTER_STAT(TEXT("Simulation: Num Warm Started Shape-Particle Contacts"),    STAT_AGXD_SimNumWarmStartedShapeParticleContacts,    STATGROUP_AGXDynamicsCounts);
DECLARE_DWORD_COUNTER_STAT(TEXT("Space Num Shapes"),                                        STAT_AGXD_SpaceNumShapes,                            STATGROUP_AGXDynamicsCounts);
DECLARE_DWORD_COUNTER_STAT(TEXT("Space Num Shape-Shape Contact Points"),                    STAT_AGXD_SpaceNumShapeShapeContactPoints,           STATGROUP_AGXDynamicsCounts);
DECLARE_DWORD_COUNTER_STAT(TEXT("Space Num Shape-Shape Contacts"),                          STAT_AGXD_SpaceNumShapeShapeContacts,                STATGROUP_AGXDynamicsCounts);
DECLARE_DWORD_COUNTER_STAT(TEXT("Space Num Particle-Particle Contacts"),                    STAT_AGXD_SpaceNumParticleParticleContacts,          STATGROUP_AGXDynamicsCounts);
DECLARE_DWORD_COUNTER_STAT(TEXT("Space Num Shape-Particle Contacts"),                       STAT_AGXD_SpaceNumShapeParticleContacts,             STATGROUP_AGXDynamicsCounts);
DECLARE_DWORD_COUNTER_STAT(TEXT("Space Num Narrow Phase Tests"),                            STAT_AGXD_SpaceNumNarrowPhaseTests,                  STATGROUP_AGXDynamicsCounts);
DECLARE_DWORD_COUNTER_STAT(TEXT("Dymamics System: Num Enabled Rigid Bodies"),               STAT_AGXD_DynSysNumEnabledRigidBodies,               STATGROUP_AGXDynamicsCounts);
DECLARE_DWORD_COUNTER_STAT(TEXT("Dymamics System: Num Binary Constraints"),                 STAT_AGXD_DynSysNumBinaryConstraints,                STATGROUP_AGXDynamicsCounts);
DECLARE_DWORD_COUNTER_STAT(TEXT("Dymamics System: Num Multi Body Constraints"),             STAT_AGXD_DynSysNumMultiBodyConstraints,             STATGROUP_AGXDynamicsCounts);
DECLARE_DWORD_COUNTER_STAT(TEXT("Dymamics System: Num Contact Constraints"),                STAT_AGXD_DynSysNumContactConstraints,               STATGROUP_AGXDynamicsCounts);
DECLARE_DWORD_COUNTER_STAT(TEXT("Dymamics System: Num Solve Islands"),                      STAT_AGXD_DynSysNumSolveIslands,                     STATGROUP_AGXDynamicsCounts);

// clang-format on
