using System;
using System.Collections.Generic;
using System.Diagnostics;
using nkast.Aether.Physics2D.Common;
using CtrEditor.Simulacion.Fluids;
using CtrEditor.ObjetosSim;

namespace CtrEditor.Simulacion
{
    /// <summary>
    /// Gestor para la simulación de fluidos independiente de la simulación física principal
    /// </summary>
    public class FluidSimulationManager
    {
        private SimulacionFluidos _simulacion;
        private readonly List<Action> _deferredActions = new List<Action>();
        private readonly List<osSistemaFluidos> _sistemasRegistrados = new List<osSistemaFluidos>();
        private float _defaultWidth = 10.0f;
        private float _defaultHeight = 10.0f;
        
        private bool _isRunning = false;
        private Stopwatch _stopwatch;
        private double _lastUpdateTime;
        
        public bool IsRunning => _isRunning;
        
        /// <summary>
        /// Constructor
        /// </summary>
        public FluidSimulationManager()
        {
            _stopwatch = new Stopwatch();
        }
        
        /// <summary>
        /// Inicializa la simulación de fluidos
        /// </summary>
        public void Initialize()
        {
            if (_simulacion == null)
            {
                _simulacion = new SimulacionFluidos(
                    _defaultWidth, 
                    _defaultHeight, 
                    10000, // max partículas
                    new Vector2(0, 9.8f) // gravedad por defecto
                );
            }
        }
        
        /// <summary>
        /// Inicia la simulación de fluidos
        /// </summary>
        public void Start()
        {
            if (!_isRunning)
            {
                _isRunning = true;
                _stopwatch.Start();
                _lastUpdateTime = _stopwatch.Elapsed.TotalMilliseconds;
                
                // Notificar a los sistemas de fluidos
                foreach (var sistema in _sistemasRegistrados)
                {
                    sistema.OnFluidSimulationStart();
                }
            }
        }
        
        /// <summary>
        /// Detiene la simulación de fluidos
        /// </summary>
        public void Stop()
        {
            if (_isRunning)
            {
                _isRunning = false;
                _stopwatch.Stop();
                _stopwatch.Reset();
                
                // Notificar a los sistemas de fluidos
                foreach (var sistema in _sistemasRegistrados)
                {
                    sistema.OnFluidSimulationStop();
                }
            }
        }
        
        /// <summary>
        /// Actualiza un paso de la simulación de fluidos
        /// </summary>
        public void Step()
        {
            if (!_isRunning) return;
            
            // Calcular delta time
            double currentTime = _stopwatch.Elapsed.TotalMilliseconds;
            float deltaTime = (float)(currentTime - _lastUpdateTime) / 1000.0f;
            _lastUpdateTime = currentTime;
            
            // Asegurar que deltaTime no es demasiado grande (evita inestabilidades)
            if (deltaTime > 0.05f) deltaTime = 0.05f;
            
            // Procesar acciones diferidas
            foreach (var action in _deferredActions)
            {
                action();
            }
            _deferredActions.Clear();
            
            // Actualizar la simulación
            _simulacion?.Actualizar(deltaTime);
            
            // Notificar a los sistemas de fluidos
            foreach (var sistema in _sistemasRegistrados)
            {
                sistema.UpdateFluidSimulation(deltaTime);
            }
        }
        
        /// <summary>
        /// Registra un sistema de fluidos para ser actualizado
        /// </summary>
        public void RegisterFluidSystem(osSistemaFluidos sistema)
        {
            if (!_sistemasRegistrados.Contains(sistema))
            {
                _sistemasRegistrados.Add(sistema);
                
                // Si el sistema ya está corriendo, notificar al nuevo sistema
                if (_isRunning)
                {
                    sistema.OnFluidSimulationStart();
                }
            }
        }
        
        /// <summary>
        /// Elimina un sistema de fluidos del registro
        /// </summary>
        public void UnregisterFluidSystem(osSistemaFluidos sistema)
        {
            _sistemasRegistrados.Remove(sistema);
        }
        
        /// <summary>
        /// Añade una acción para ser ejecutada en el próximo paso de simulación
        /// </summary>
        public void AddDeferredAction(Action action)
        {
            _deferredActions.Add(action);
        }
        
        /// <summary>
        /// Obtiene la instancia de simulación de fluidos
        /// </summary>
        public SimulacionFluidos GetSimulacion()
        {
            if (_simulacion == null)
            {
                Initialize();
            }
            return _simulacion;
        }
        
        /// <summary>
        /// Limpia los recursos de la simulación
        /// </summary>
        public void Clear()
        {
            Stop();
            _simulacion = null;
            _sistemasRegistrados.Clear();
            _deferredActions.Clear();
        }
    }
}
