using System.Collections.Generic;
using UnityEngine;

namespace FrameDoctor.Demo
{
    /// <summary>
    /// Generates various types of performance load for demonstrating FrameDoctor's
    /// profiler capture and analysis capabilities.
    /// </summary>
    public class DemoLoadGenerator : MonoBehaviour
    {
        [Header("CPU Load")]
        [Tooltip("Enable CPU-intensive calculations")]
        public bool generateCPULoad = true;
        [Range(100, 10000)]
        public int cpuIterations = 1000;

        [Header("Memory/GC Load")]
        [Tooltip("Enable garbage collection allocations")]
        public bool generateGCLoad = true;
        [Range(10, 500)]
        public int allocationsPerFrame = 50;
        [Range(100, 10000)]
        public int allocationSize = 1000;

        [Header("Rendering Load")]
        [Tooltip("Enable dynamic object spawning")]
        public bool generateRenderLoad = true;
        [Range(10, 500)]
        public int objectCount = 100;
        public GameObject objectPrefab;

        [Header("Animation")]
        public bool rotateObjects = true;
        public float rotationSpeed = 50f;

        private List<GameObject> _spawnedObjects = new List<GameObject>();
        private List<string> _gcPressure = new List<string>();

        void Start()
        {
            if (generateRenderLoad)
            {
                SpawnObjects();
            }
        }

        void Update()
        {
            if (generateCPULoad)
            {
                SimulateCPUWork();
            }

            if (generateGCLoad)
            {
                SimulateGCAllocations();
            }

            if (rotateObjects)
            {
                RotateSpawnedObjects();
            }
        }

        /// <summary>
        /// Performs CPU-intensive calculations to create profiler load
        /// </summary>
        private void SimulateCPUWork()
        {
            float result = 0;
            for (int i = 0; i < cpuIterations; i++)
            {
                result += Mathf.Sin(i * Time.time) * Mathf.Cos(i * 0.5f);
                result = Mathf.Sqrt(Mathf.Abs(result) + 1);
            }
        }

        /// <summary>
        /// Creates garbage collection pressure by allocating strings
        /// </summary>
        private void SimulateGCAllocations()
        {
            _gcPressure.Clear();
            for (int i = 0; i < allocationsPerFrame; i++)
            {
                // Intentionally creating garbage for demo purposes
                _gcPressure.Add(new string('x', allocationSize));
            }
        }

        /// <summary>
        /// Spawns objects in a grid pattern to create rendering load
        /// </summary>
        private void SpawnObjects()
        {
            // Clear existing objects
            foreach (var obj in _spawnedObjects)
            {
                if (obj != null) Destroy(obj);
            }
            _spawnedObjects.Clear();

            int gridSize = Mathf.CeilToInt(Mathf.Sqrt(objectCount));
            float spacing = 2f;

            for (int i = 0; i < objectCount; i++)
            {
                int x = i % gridSize;
                int z = i / gridSize;
                Vector3 position = new Vector3(
                    (x - gridSize / 2f) * spacing,
                    0,
                    (z - gridSize / 2f) * spacing
                );

                GameObject obj;
                if (objectPrefab != null)
                {
                    obj = Instantiate(objectPrefab, position, Quaternion.identity, transform);
                }
                else
                {
                    // Create default cube if no prefab assigned
                    obj = GameObject.CreatePrimitive(PrimitiveType.Cube);
                    obj.transform.position = position;
                    obj.transform.parent = transform;

                    // Add random color
                    var renderer = obj.GetComponent<Renderer>();
                    if (renderer != null)
                    {
                        renderer.material.color = Random.ColorHSV(0f, 1f, 0.5f, 1f, 0.5f, 1f);
                    }
                }

                _spawnedObjects.Add(obj);
            }
        }

        /// <summary>
        /// Rotates all spawned objects to create continuous rendering updates
        /// </summary>
        private void RotateSpawnedObjects()
        {
            float rotation = rotationSpeed * Time.deltaTime;
            foreach (var obj in _spawnedObjects)
            {
                if (obj != null)
                {
                    obj.transform.Rotate(Vector3.up, rotation);
                    obj.transform.Rotate(Vector3.right, rotation * 0.5f);
                }
            }
        }

        /// <summary>
        /// Respawn objects (can be called from UI)
        /// </summary>
        public void RespawnObjects()
        {
            SpawnObjects();
        }

        void OnDestroy()
        {
            foreach (var obj in _spawnedObjects)
            {
                if (obj != null) Destroy(obj);
            }
            _spawnedObjects.Clear();
        }
    }
}
