using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Media;
using CtrEditor.HydraulicSimulator;
using CtrEditor.ObjetosSim;
using CtrEditor.FuncionesBase;
using HydraulicSimulator.Models;
using Newtonsoft.Json;
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
using CommunityToolkit.Mvvm.ComponentModel;

namespace CtrEditor.ObjetosSim.HydraulicComponents
{
    /// <summary>
    /// Bomba hidráulica que implementa las interfaces del simulador hidráulico
    /// </summary>
    public partial class osHydPump : osBase, IHydraulicPump, IosBase
    {
        #region Properties
        
        private double _pumpHead = 50.0; // metros
        private double _maxFlow = 0.01; // m³/s (36 m³/h)
        private double _speedRatio = 1.0;
        private bool _isRunning = true;
        private int _pumpDirection = 1;
        private double _currentFlow = 0.0;
        private double _currentPressure = 0.0;
        
        // Propiedades visuales
        [ObservableProperty]
        [property: Category("🎨 Apariencia")]
        [property: Description("Ancho de la bomba en metros")]
        [property: Name("Ancho")]
        private float ancho = 0.15f;

        [ObservableProperty]
        [property: Category("🎨 Apariencia")]
        [property: Description("Alto de la bomba en metros")]
        [property: Name("Alto")]
        private float alto = 0.10f;

        [ObservableProperty]
        [property: Category("🎨 Apariencia")]
        [property: Description("Color visual de la bomba")]
        [property: Name("Color")]
        private Brush colorButton_oculto = Brushes.Blue;

        [ObservableProperty]
        [property: Category("🎨 Apariencia")]
        [property: Description("Ángulo de rotación de la bomba en grados")]
        [property: Name("Ángulo")]
        private float angulo = 0f;
        
        [Category("🔧 Bomba Hidráulica")]
        [DisplayName("Cabeza de bomba")]
        [Description("Cabeza de la bomba a caudal cero (m)")]
        public double PumpHead
        {
            get => _pumpHead;
            set
            {
                if (SetProperty(ref _pumpHead, Math.Max(0, value)))
                {
                    InvalidateHydraulicNetwork();
                }
            }
        }
        
        [Category("🔧 Bomba Hidráulica")]
        [DisplayName("Caudal máximo")]
        [Description("Caudal máximo de la bomba (m³/s)")]
        public double MaxFlow
        {
            get => _maxFlow;
            set
            {
                if (SetProperty(ref _maxFlow, Math.Max(0.001, value)))
                {
                    InvalidateHydraulicNetwork();
                }
            }
        }
        
        [Category("🔧 Bomba Hidráulica")]
        [DisplayName("Velocidad relativa")]
        [Description("Velocidad relativa de la bomba (0.0 a 1.0)")]
        public double SpeedRatio
        {
            get => _speedRatio;
            set
            {
                SetProperty(ref _speedRatio, Math.Max(0.0, Math.Min(1.0, value)));
            }
        }
        
        [Category("🔧 Bomba Hidráulica")]
        [DisplayName("Funcionando")]
        [Description("Indica si la bomba está encendida")]
        public bool IsRunning
        {
            get => _isRunning;
            set
            {
                SetProperty(ref _isRunning, value);
            }
        }
        
        [Category("🔧 Bomba Hidráulica")]
        [DisplayName("Dirección")]
        [Description("Dirección de la bomba (+1 o -1)")]
        [ItemsSource(typeof(PumpDirectionItemsSource))]
        public int PumpDirection
        {
            get => _pumpDirection;
            set
            {
                if (SetProperty(ref _pumpDirection, value == -1 ? -1 : 1))
                {
                    InvalidateHydraulicNetwork();
                }
            }
        }
        
        [Category("📊 Estado Actual")]
        [DisplayName("Caudal actual")]
        [Description("Caudal actual de la bomba (m³/s)")]
        [JsonIgnore]
        public double CurrentFlow
        {
            get => _currentFlow;
            private set => SetProperty(ref _currentFlow, value);
        }
        
        [Category("📊 Estado Actual")]
        [DisplayName("Presión actual")]
        [Description("Presión actual en la bomba (Pa)")]
        [JsonIgnore]
        public double CurrentPressure
        {
            get => _currentPressure;
            private set => SetProperty(ref _currentPressure, value);
        }
        
        [Category("📊 Estado Actual")]
        [DisplayName("Presión (bar)")]
        [Description("Presión actual en la bomba (bar)")]
        [JsonIgnore]
        public double CurrentPressureBar => CurrentPressure / 100000.0;
        
        [Category("📊 Estado Actual")]
        [DisplayName("Caudal (L/min)")]
        [Description("Caudal actual en L/min")]
        [JsonIgnore]
        public double CurrentFlowLMin => CurrentFlow * 60000.0; // m³/s a L/min
        
        #endregion
        
        #region Constructor y Métodos Base

        private string nombre = NombreClase();

        [Category("🏷️ Identificación")]
        [Description("Nombre identificativo del objeto")]
        [Name("Nombre")]
        public override string Nombre
        {
            get => nombre;
            set => SetProperty(ref nombre, value);
        }

        public override void OnMove(float LeftPixels, float TopPixels)
        {
            // Los objetos hidráulicos no necesitan actualizar geometría física
        }

        public override void OnResize(float Delta_Width, float Delta_Height)
        {
            Ancho += Delta_Width;
            Alto += Delta_Height;
        }

        public osHydPump()
        {
            Nombre = "Bomba Hidráulica";
        }

        public override void UpdateGeometryStart()
        {
            // Los objetos hidráulicos se registran automáticamente 
            // cuando inicia la simulación a través de las interfaces
        }

        public override void UpdateGeometryStep()
        {
            // Los objetos hidráulicos actualizan sus resultados 
            // a través de ApplyHydraulicResults()
        }

        public override void UpdateControl(int elapsedMilliseconds)
        {
            // Actualizar el color según el estado
            if (IsRunning)
                ColorButton_oculto = Brushes.Green;
            else
                ColorButton_oculto = Brushes.Gray;
        }

        public override void ucLoaded()
        {
            // Los objetos hidráulicos no necesitan geometría física
            base.ucLoaded();
        }

        public override void ucUnLoaded()
        {
            // Los objetos hidráulicos no tienen geometría que limpiar
        }

        #endregion
        
        #region IHydraulicComponent Implementation
        
        [JsonIgnore]
        public bool HasHydraulicComponents => true;
        
        public List<HydraulicNodeDefinition> GetHydraulicNodes()
        {
            var nodes = new List<HydraulicNodeDefinition>
            {
                new HydraulicNodeDefinition($"{Nombre}_In", false, null, "Entrada de la bomba"),
                new HydraulicNodeDefinition($"{Nombre}_Out", false, null, "Salida de la bomba")
            };
            
            return nodes;
        }
        
        public List<HydraulicElementDefinition> GetHydraulicElements()
        {
            var elements = new List<HydraulicElementDefinition>();
            
            if (HasHydraulicComponents)
            {
                // Crear bomba con parámetros actuales
                var pump = new PumpHQ(
                    h0: PumpHead,
                    q0: MaxFlow,
                    speedRel: IsRunning ? SpeedRatio : 0.0, // Si no está funcionando, velocidad = 0
                    direction: PumpDirection
                );
                
                var pumpElement = new HydraulicElementDefinition(
                    $"{Nombre}_Pump",
                    $"{Nombre}_In",
                    $"{Nombre}_Out",
                    pump,
                    $"Bomba {Nombre}"
                );
                
                elements.Add(pumpElement);
            }
            
            return elements;
        }
        
        public void UpdateHydraulicProperties()
        {
            // Aquí se pueden hacer validaciones o ajustes antes de la simulación
            if (!IsRunning)
            {
                SpeedRatio = 0.0;
            }
            
            if (SpeedRatio < 0.0) SpeedRatio = 0.0;
            if (SpeedRatio > 1.0) SpeedRatio = 1.0;
            
            Debug.WriteLine($"Bomba {Nombre}: Velocidad={SpeedRatio:F2}, Funcionando={IsRunning}");
        }
        
        public void ApplyHydraulicResults(Dictionary<string, double> flows, Dictionary<string, double> pressures)
        {
            // Buscar resultados para esta bomba
            string pumpBranchName = $"{Nombre}_Pump";
            string inletNodeName = $"{Nombre}_In";
            string outletNodeName = $"{Nombre}_Out";
            
            if (flows.ContainsKey(pumpBranchName))
            {
                CurrentFlow = flows[pumpBranchName];
            }
            
            if (pressures.ContainsKey(inletNodeName))
            {
                CurrentPressure = pressures[inletNodeName];
            }
            else if (pressures.ContainsKey(outletNodeName))
            {
                CurrentPressure = pressures[outletNodeName];
            }
        }
        
        #endregion
        
        #region IHydraulicFlowReceiver Implementation
        
        public void SetFlow(double flow)
        {
            CurrentFlow = flow;
        }
        
        public double GetFlow()
        {
            return CurrentFlow;
        }
        
        #endregion
        
        #region IHydraulicPressureReceiver Implementation
        
        public void SetPressure(double pressure)
        {
            CurrentPressure = pressure;
        }
        
        public double GetPressure()
        {
            return CurrentPressure;
        }
        
        #endregion
        
        #region Helper Methods
        
        /// <summary>
        /// Invalida la red hidráulica para forzar reconstrucción
        /// </summary>
        private void InvalidateHydraulicNetwork()
        {
            // Si tenemos acceso al MainViewModel, invalidar la red
            if (_mainViewModel?.hydraulicSimulationManager != null)
            {
                _mainViewModel.hydraulicSimulationManager.InvalidateNetwork();
            }
        }
        
        #endregion
        
        #region Static Interface Implementation
        
        public static string NombreClase() => "Bomba Hidráulica";
        public static string NombreCategoria() => "Componentes Hidráulicos";
        
        #endregion
    }
    
    /// <summary>
    /// Proveedor de items para la dirección de la bomba
    /// </summary>
    public class PumpDirectionItemsSource : IItemsSource
    {
        public Xceed.Wpf.Toolkit.PropertyGrid.Attributes.ItemCollection GetValues()
        {
            var items = new Xceed.Wpf.Toolkit.PropertyGrid.Attributes.ItemCollection();
            items.Add(1, "Adelante (+1)");
            items.Add(-1, "Atrás (-1)");
            return items;
        }
    }
}
