using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using CtrEditor.FuncionesBase;
using CtrEditor.Simulacion.Fluids;
using tainicom.Aether.Physics2D.Fluids;

namespace CtrEditor.ObjetosSim
{
    /// <summary>
    /// Lógica para ucSistemaFluidos.xaml
    /// </summary>
    public partial class ucSistemaFluidos : UserControl, IDataContainer
    {
        public osBase? Datos { get; set; }
        public int zIndex_fromFrames { get; set; }
        
        // Host para el sistema visual de partículas
        private ParticulasFluidoHost _hostVisual;
        
        // Timer para medir FPS
        private DateTime _ultimaActualizacion = DateTime.Now;
        private int _contadorFrames = 0;
        private double _fps = 0;
        
        public ucSistemaFluidos()
        {
            InitializeComponent();
            this.Loaded += OnLoaded;
            this.Unloaded += OnUnloaded;
            
            // Inicializar el host visual y agregarlo al contenedor
            _hostVisual = new ParticulasFluidoHost();
            ContenedorVisual.Children.Add(_hostVisual);
            
            // Configurar actualizaciones periódicas para FPS
            CompositionTarget.Rendering += OnRendering;
        }
        
        private void OnRendering(object sender, EventArgs e)
        {
            _contadorFrames++;
            
            // Calcular FPS cada segundo
            TimeSpan elapsed = DateTime.Now - _ultimaActualizacion;
            if (elapsed.TotalSeconds >= 1)
            {
                _fps = _contadorFrames / elapsed.TotalSeconds;
                _contadorFrames = 0;
                _ultimaActualizacion = DateTime.Now;
                
                if (Datos is osSistemaFluidos vm)
                {
                    vm.Fps = _fps;
                }
            }
            
            // Actualizar la visualización de partículas
            ActualizarVisualizacion();
        }
        
        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            Datos?.ucLoaded();
        }
        
        private void OnUnloaded(object sender, RoutedEventArgs e)
        {
            Datos?.ucUnLoaded();
            CompositionTarget.Rendering -= OnRendering;
        }
        
        public void Highlight(bool State) { }
        
        public ZIndexEnum ZIndex_Base()
        {
            return ZIndexEnum.Dinamicos;
        }
        
        /// <summary>
        /// Actualiza la visualización de partículas
        /// </summary>
        private void ActualizarVisualizacion()
        {
            if (Datos is osSistemaFluidos viewModel)
            {
                // Obtener la simulación activa desde el ViewModel
                var simulacion = viewModel._simFluidos?.SistemaFluido;
                if (simulacion != null)
                {
                    // Configurar propiedades visuales
                    float tamañoParticula = viewModel.TamañoParticula;
                    Color colorFluido = viewModel.ColorFluido;
                    
                    // Actualizar la visualización
                    _hostVisual.ActualizarParticulasFluido(simulacion.Particles, tamañoParticula, colorFluido, viewModel.OpacidadParticulas);
                }
            }
        }
    }
    
    /// <summary>
    /// Clase que maneja el rendering optimizado de partículas usando DrawingVisual
    /// </summary>
    public class ParticulasFluidoHost : FrameworkElement
    {
        private readonly DrawingVisual _visual = new DrawingVisual();
        private readonly MeterToPixelConverter _converter = new MeterToPixelConverter();
        
        public ParticulasFluidoHost()
        {
            AddVisualChild(_visual);
        }
        
        protected override int VisualChildrenCount => 1;
        
        protected override Visual GetVisualChild(int index)
        {
            if (index != 0)
                throw new ArgumentOutOfRangeException();
            
            return _visual;
        }
        
        /// <summary>
        /// Actualiza la visualización de las partículas de fluido
        /// </summary>
        /// <param name="particulas">Lista de partículas a visualizar</param>
        /// <param name="tamañoParticula">Tamaño de las partículas en metros</param>
        /// <param name="colorFluido">Color base del fluido</param>
        /// <param name="opacidadBase">Opacidad base de las partículas</param>
        public void ActualizarParticulasFluido(IEnumerable<Particle> particulas, 
                                               float tamañoParticula, 
                                               Color colorFluido,
                                               double opacidadBase)
        {
            using (DrawingContext dc = _visual.RenderOpen())
            {
                foreach (var particula in particulas)
                {
                    // Ignorar partículas inactivas u ocultas
                    if (particula == null)
                        continue;
                    
                    // Convertir posición a píxeles
                    float x = (float)_converter.Convert((particula.Position.X / 100) + 5, null, null, null);
                    float y = (float)_converter.Convert(particula.Position.Y / 100, null, null, null);
                    float radio = (float)_converter.Convert(tamañoParticula / 2, null, null, null);
                    
                    // Calcular opacidad basada en densidad
                    double opacidad = Math.Clamp(particula.Density / 15.0, 0.4, 0.9) * opacidadBase;
                    
                    // Calcular color basado en velocidad (opcional)
                    Color colorFinal = colorFluido;
                    double velocidad = Math.Sqrt(particula.Velocity.X * particula.Velocity.X + 
                                               particula.Velocity.Y * particula.Velocity.Y);
                    
                    if (velocidad > 50)
                    {
                        // Partículas más rápidas tienden a ser más claras
                        float factor = Math.Min(1.0f, (float)velocidad / 400);
                        colorFinal = MezclarColores(colorFluido, Colors.White, factor);
                    }
                    
                    SolidColorBrush brush = new SolidColorBrush(colorFinal) { Opacity = opacidad };
                    
                    // Dibujar partícula
                    dc.DrawEllipse(brush, null, new Point(x, y), radio, radio);
                }
            }
            
            InvalidateVisual();
        }
        
        /// <summary>
        /// Mezcla dos colores según un factor (0-1)
        /// </summary>
        private Color MezclarColores(Color color1, Color color2, float factor)
        {
            byte r = (byte)(color1.R + (color2.R - color1.R) * factor);
            byte g = (byte)(color1.G + (color2.G - color1.G) * factor);
            byte b = (byte)(color1.B + (color2.B - color1.B) * factor);
            return Color.FromRgb(r, g, b);
        }
    }
}
