using System;
using System.Collections.Generic;
using HydraulicSimulator.Models;
using CtrEditor.HydraulicSimulator;
using CtrEditor.ObjetosSim.HydraulicComponents;

namespace CtrEditor.HydraulicSimulator.Examples
{
    /// <summary>
    /// Ejemplo de uso de los componentes hidráulicos según la documentación
    /// Muestra cómo crear una red simple: Bomba -> Tubería -> Tanque de Descarga
    /// </summary>
    public class SimpleHydraulicSystemExample
    {
        /// <summary>
        /// Crea un sistema hidráulico simple con bomba, tubería y tanque
        /// </summary>
        public static void RunExample()
        {
            Console.WriteLine("🚀 Iniciando ejemplo de sistema hidráulico simple");
            Console.WriteLine("Sistema: Bomba -> Tubería -> Tanque de Descarga");
            Console.WriteLine();

            // 1. Crear la red hidráulica
            var network = new HydraulicNetwork();

            // 2. Agregar nodos según la documentación
            network.AddNode("SUMINISTRO", 0);          // Tanque de suministro a presión atmosférica
            network.AddNode("BOMBA_OUT");              // Salida de bomba (presión calculada)
            network.AddNode("TANQUE_DESCARGA", 0);     // Tanque de descarga libre

            // 3. Crear elementos hidráulicos
            var pump = new PumpHQ(
                h0: 80,        // Cabeza a caudal cero: 80 metros
                q0: 0.01,      // Caudal a cabeza cero: 0.01 m³/s (36 m³/h)
                speedRel: 1.0, // Velocidad nominal
                direction: 1   // Dirección normal
            );

            var pipe = new Pipe(
                length: 50,         // 50 metros de longitud
                diameter: 0.08,     // 80mm de diámetro
                roughness: 0.0015   // Rugosidad del acero comercial
            );

            // 4. Conectar elementos en ramas según la documentación
            network.AddBranch("SUMINISTRO", "BOMBA_OUT", 
                new List<Element> { pump }, "Bomba_Principal");
                
            network.AddBranch("BOMBA_OUT", "TANQUE_DESCARGA", 
                new List<Element> { pipe }, "Tuberia_Descarga");

            // 5. Resolver la red
            Console.WriteLine("⚙️  Resolviendo red hidráulica...");
            var result = network.Solve(
                maxIterations: 200,
                tolerance: 1e-4,
                verbose: true
            );

            // 6. Mostrar resultados
            if (result.Converged)
            {
                Console.WriteLine("✅ Simulación exitosa!");
                Console.WriteLine($"Convergió en {result.Iterations} iteraciones");
                Console.WriteLine();
                
                ShowResults(result);
                ShowComponentAnalysis(result, pump, pipe);
            }
            else
            {
                Console.WriteLine($"❌ No convergió después de {result.Iterations} iteraciones");
                Console.WriteLine($"Error final: {result.Residual:E6}");
            }
        }

        private static void ShowResults(SolutionResult result)
        {
            Console.WriteLine("📊 RESULTADOS DE LA SIMULACIÓN:");
            Console.WriteLine("═══════════════════════════════");
            
            // Flujos
            Console.WriteLine("🌊 Flujos:");
            foreach (var flow in result.Flows)
            {
                double flowM3h = flow.Value * 3600; // Convertir a m³/h
                double flowLmin = flow.Value * 60000; // Convertir a L/min
                Console.WriteLine($"  {flow.Key}:");
                Console.WriteLine($"    {flow.Value:F6} m³/s = {flowM3h:F2} m³/h = {flowLmin:F1} L/min");
            }
            
            Console.WriteLine();
            
            // Presiones
            Console.WriteLine("📈 Presiones:");
            foreach (var pressure in result.Pressures)
            {
                double pressureBar = pressure.Value / 100000.0; // Convertir a bar
                double pressureKPa = pressure.Value / 1000.0;   // Convertir a kPa
                Console.WriteLine($"  {pressure.Key}:");
                Console.WriteLine($"    {pressure.Value:F0} Pa = {pressureKPa:F1} kPa = {pressureBar:F3} bar");
            }
        }

        private static void ShowComponentAnalysis(SolutionResult result, PumpHQ pump, Pipe pipe)
        {
            Console.WriteLine();
            Console.WriteLine("🔧 ANÁLISIS DE COMPONENTES:");
            Console.WriteLine("═══════════════════════════");
            
            // Análisis de la bomba
            if (result.Flows.TryGetValue("Bomba_Principal", out double pumpFlow))
            {
                double pumpFlowM3h = pumpFlow * 3600;
                double pumpHead = pump.Dp(pumpFlow, Fluid.Water20C) / (1000 * 9.81); // Convertir Pa a metros
                double pumpPower = pumpFlow * pump.Dp(pumpFlow, Fluid.Water20C) / 1000; // Potencia hidráulica en kW
                
                Console.WriteLine("💨 Bomba:");
                Console.WriteLine($"  Caudal: {pumpFlowM3h:F1} m³/h");
                Console.WriteLine($"  Cabeza: {pumpHead:F1} m");
                Console.WriteLine($"  Potencia hidráulica: {pumpPower:F2} kW");
            }
            
            // Análisis de la tubería
            if (result.Flows.TryGetValue("Tuberia_Descarga", out double pipeFlow))
            {
                double pipePressureDrop = pipe.Dp(pipeFlow, Fluid.Water20C);
                double pipeHeadLoss = pipePressureDrop / (1000 * 9.81); // Convertir Pa a metros
                double velocity = Math.Abs(pipeFlow) / (Math.PI * (pipe.D * pipe.D) / 4.0);
                
                Console.WriteLine();
                Console.WriteLine("🚰 Tubería:");
                Console.WriteLine($"  Caudal: {pipeFlow * 3600:F1} m³/h");
                Console.WriteLine($"  Velocidad: {velocity:F2} m/s");
                Console.WriteLine($"  Pérdida de carga: {pipeHeadLoss:F2} m");
                Console.WriteLine($"  Pérdida de presión: {pipePressureDrop / 1000:F1} kPa");
            }
        }

        /// <summary>
        /// Ejemplo de cómo los objetos gráficos osHyd* se integrarían en la simulación
        /// </summary>
        public static void ShowGraphicObjectsIntegration()
        {
            Console.WriteLine();
            Console.WriteLine("🎨 INTEGRACIÓN CON OBJETOS GRÁFICOS:");
            Console.WriteLine("═══════════════════════════════════");
            Console.WriteLine();
            Console.WriteLine("Los objetos creados (osHydPump, osHydPipe, osHydDischargeTank)");
            Console.WriteLine("se integran automáticamente en el sistema de la siguiente manera:");
            Console.WriteLine();
            Console.WriteLine("1. 📋 Registro automático:");
            Console.WriteLine("   - Se registran por reflexión usando NombreCategoria() = \"Hidráulicos\"");
            Console.WriteLine("   - Aparecen en la categoría \"Hidráulicos\" del editor");
            Console.WriteLine();
            Console.WriteLine("2. 🔗 Sistema de conexiones:");
            Console.WriteLine("   - Usan ItemsSource<IHydraulicComponent> para filtrar componentes");
            Console.WriteLine("   - Similar al sistema Motor/Transporte existente");
            Console.WriteLine("   - Conexiones: Id_InletComponent, Id_OutletComponent");
            Console.WriteLine();
            Console.WriteLine("3. 🚫 No participan en Bepu:");
            Console.WriteLine("   - Override Start() sin crear geometrías Bepu");
            Console.WriteLine("   - Solo participan en el simulador hidráulico");
            Console.WriteLine();
            Console.WriteLine("4. 📊 Integración con HydraulicSimulationManager:");
            Console.WriteLine("   - Implementan IHydraulicComponent para GetHydraulicNodes()");
            Console.WriteLine("   - Implementan GetHydraulicElements() para el solver");
            Console.WriteLine("   - Reciben resultados via ApplyHydraulicResults()");
            Console.WriteLine();
            Console.WriteLine("5. 🎯 Ejemplo de configuración:");
            Console.WriteLine("   osHydPump (Nombre=\"Bomba_01\", H0=80m, Q0=36m³/h)");
            Console.WriteLine("        ↓ (Id_OutletComponent=\"Tuberia_01\")");
            Console.WriteLine("   osHydPipe (Nombre=\"Tuberia_01\", L=50m, D=80mm)");
            Console.WriteLine("        ↓ (Id_OutletComponent=\"Tanque_01\")");
            Console.WriteLine("   osHydDischargeTank (Nombre=\"Tanque_01\", Area=1m²)");
        }
    }
}
