using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using CommunityToolkit.Mvvm.ComponentModel;
using CtrEditor.Siemens;
using CtrEditor.Simulacion;
using SkiaSharp;

namespace CtrEditor.ObjetosSim
{
    /// <summary>
    /// Interaction logic for ucTransporteGuiasUnion.xaml
    /// </summary>
    public partial class osTransporteGuiasUnion : osBase, IosBase
    {
        private osBase _osMotorA = null;
        private osBase _osMotorB = null;

        Dictionary<Rectangle, simTransporte> SimGeometriaT;
        Dictionary<Rectangle, simGuia> SimGeometriaG;
        Dictionary<Rectangle, Storyboard> Storyboards;
        Dictionary<Rectangle, BoolReference> TransportsDirection;
        Dictionary<Rectangle, FloatReference> TransportsVelocidad;

        public static string NombreClase()
        {
            return "Transporte Guias Union";
        }
        private string nombre = NombreClase();
        public override string Nombre
        {
            get => nombre;
            set => SetProperty(ref nombre, value);
        }

        [ObservableProperty]
        Color color;

        [ObservableProperty]
        public string motorA;

        partial void OnMotorAChanged(string value)
        {
            _osMotorA = ObtenerLink(MotorA, typeof(osVMmotorSim));
        }

        [ObservableProperty]
        public float velocidadActualA;

        partial void OnVelocidadActualAChanged(float value)
        {
            if (_visualRepresentation is ucTransporteGuiasUnion uc)
            {
                var transporte = uc.TransporteA;
                SetSpeed(transporte);
            }
        }

        [ObservableProperty]
        bool invertirDireccionA;

        partial void OnInvertirDireccionAChanged(bool value)
        {
            if (_visualRepresentation is ucTransporteGuiasUnion uc)
            {
                var transporte = uc.TransporteA;

                SetSpeed(transporte);
                ActualizarStoryboards(transporte);
            }
        }



        [ObservableProperty]
        public string motorB;

        partial void OnMotorBChanged(string value)
        {
            _osMotorB = ObtenerLink(MotorB, typeof(osVMmotorSim));
        }

        [ObservableProperty]
        public float velocidadActualB;

        partial void OnVelocidadActualBChanged(float value)
        {
            if (_visualRepresentation is ucTransporteGuiasUnion uc)
            {
                var transporte = uc.TransporteB;
                SetSpeed(transporte);
            }
        }

        [ObservableProperty]
        bool invertirDireccionB;

        partial void OnInvertirDireccionBChanged(bool value)
        {
            if (_visualRepresentation is ucTransporteGuiasUnion uc)
            {
                var transporte = uc.TransporteB;

                SetSpeed(transporte);
                ActualizarStoryboards(transporte);
            }
        }


        [ObservableProperty]
        public float anchoRecto;
        [ObservableProperty]
        public float anchoCentral;


        partial void OnAnchoRectoChanged(float value)
        {
            AnchoTransporte_oculto = anchoRecto + anchoCentral;
        }

        partial void OnAnchoCentralChanged(float value)
        {
            AnchoTransporte_oculto = anchoRecto + anchoCentral;
        }

        [ObservableProperty]
        public float anchoTransporte_oculto;        

        [ObservableProperty]
        public float alto;

        partial void OnAltoChanged(float value)
        {
           // ActualizarGeometrias();
        }

        [ObservableProperty]
        public float angulo;
        [ObservableProperty]
        public float frictionCoefficient;
        [ObservableProperty]
        public float velMax50hz;
        [ObservableProperty]
        public float tiempoRampa;
        [ObservableProperty]
        public bool esMarcha;
        [ObservableProperty]
        private float distance;
        [ObservableProperty]
        private float altoGuia;

        void ActualizarStoryboards(Rectangle transporte)
        {
            if (!Storyboards.Keys.Contains(transporte)) return;

            var direccion = TransportsDirection[transporte].Value;
            var velocidad = TransportsVelocidad[transporte].Value;

            Storyboards[transporte] = CrearAnimacionMultiStoryBoardTrasnporte(Storyboards[transporte], transporte, direccion);
            ActualizarAnimacionMultiStoryBoardTransporte(Storyboards[transporte], velocidad);
        }

        void SetSpeed(Rectangle transporte)
        {
            if (!Storyboards.Keys.Contains(transporte)) return;

            var invertirDireccion = TransportsDirection[transporte].Value;
            var velocidad = TransportsVelocidad[transporte].Value;

            if (invertirDireccion)
                SimGeometriaT[transporte]?.SetSpeed(-velocidad);
            else
                SimGeometriaT[transporte]?.SetSpeed(velocidad);

            ActualizarAnimacionMultiStoryBoardTransporte(Storyboards[transporte], velocidad);
        }

        private void ActualizarGeometrias()
        {
            if (_visualRepresentation is ucTransporteGuiasUnion uc)
            {
                foreach (var transporte in SimGeometriaT)
                {
                    UpdateRectangle(transporte.Value, transporte.Key, Alto, AnchoTransporte_oculto, Angulo);
                    ActualizarStoryboards(transporte.Key);
                    SetSpeed(transporte.Key);
                }
                foreach (var l in SimGeometriaG)
                    UpdateOrCreateLine(l.Value, l.Key);

            }
        }


        public osTransporteGuiasUnion()
        {
            AnchoRecto = 0.5f;
            AnchoCentral = 0.5f;
            Alto = 0.10f;
            AltoGuia = 0.03f;
            Distance = 0.02f;
            SimGeometriaT = new Dictionary<Rectangle, simTransporte>();
            SimGeometriaG = new Dictionary<Rectangle, simGuia>();
            Storyboards = new Dictionary<Rectangle, Storyboard>();
            TransportsDirection = new Dictionary<Rectangle, BoolReference>();
            TransportsVelocidad = new Dictionary<Rectangle, FloatReference>();
        }

        public override void UpdateGeometryStart()
        {
            // Se llama antes de la simulacion
            ActualizarGeometrias();
        }

        public override void SimulationStop()
        {
            // Se llama al detener la simulacion
            if (_visualRepresentation is ucTransporteGuiasUnion uc)
            {
                SetSpeed(uc.TransporteB);
                SetSpeed(uc.TransporteA);
            }
        }

        public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
        {
            if (_osMotorA != null)
            {
                if (_osMotorA is osVMmotorSim motor)
                    VelocidadActualA = motor.Velocidad;
            }
            else if (MotorA.Length > 0)
                _osMotorA = ObtenerLink(MotorA, typeof(osVMmotorSim));

            if (_osMotorB != null)
            {
                if (_osMotorB is osVMmotorSim motor)
                    VelocidadActualB = motor.Velocidad;
            }
            else if (MotorB.Length > 0)
                _osMotorB = ObtenerLink(MotorB, typeof(osVMmotorSim));

        }

        public override void ucLoaded()
        {
            // El UserControl ya se ha cargado y podemos obtener las coordenadas para 
            // crear el objeto de simulacion
            ActualizarLeftTop();

            // El UserControl ya se ha cargado y podemos obtener las coordenadas para 
            // crear el objeto de simulacion
            if (_visualRepresentation is ucTransporteGuiasUnion uc)
            {
                foreach (var child in uc.Canvas.Children)
                    if (child is Rectangle rect)
                        if (rect.Name.StartsWith("Transporte"))
                        {
                            SimGeometriaT.Add(rect,AddRectangle(simulationManager, rect, Alto, AnchoTransporte_oculto, Angulo));
                            Storyboards.Add(rect,CrearAnimacionMultiStoryBoardTrasnporte(rect,false));                            
                        }

                foreach (var child in uc.GuiaSuperior.Canvas.Children)
                    if (child is Rectangle rect)
                        SimGeometriaG.Add(rect, AddLine(simulationManager, rect));

                foreach (var child in uc.GuiaInferior.Canvas.Children)
                    if (child is Rectangle rect)
                        SimGeometriaG.Add(rect, AddLine(simulationManager, rect));

                TransportsDirection.Add(uc.TransporteA, new BoolReference(() => InvertirDireccionA, value => InvertirDireccionA = value));
                TransportsDirection.Add(uc.TransporteB, new BoolReference(() => InvertirDireccionB, value => InvertirDireccionB = value));

                TransportsVelocidad.Add(uc.TransporteA, new FloatReference(() => VelocidadActualA, value => VelocidadActualA = value));
                TransportsVelocidad.Add(uc.TransporteB, new FloatReference(() => VelocidadActualB, value => VelocidadActualB = value));

            }
            OnMotorAChanged(MotorA);
        }


        public override void ucUnLoaded()
        {
            // El UserControl se esta eliminando
            // eliminar el objeto de simulacion
            foreach (var s in SimGeometriaT)
                simulationManager.Remove(s.Value);
            foreach (var s in SimGeometriaG)
                simulationManager.Remove(s.Value);
        }


    }

    public class BoolReference
    {
        private Func<bool> getter;
        private Action<bool> setter;

        public BoolReference(Func<bool> getter, Action<bool> setter)
        {
            this.getter = getter;
            this.setter = setter;
        }

        public bool Value
        {
            get => getter();
            set => setter(value);
        }
    }

    public class FloatReference
    {
        private Func<float> getter;
        private Action<float> setter;

        public FloatReference(Func<float> getter, Action<float> setter)
        {
            this.getter = getter;
            this.setter = setter;
        }

        public float Value
        {
            get => getter();
            set => setter(value);
        }
    }


    public partial class ucTransporteGuiasUnion : UserControl, IDataContainer
    {
        public osBase? Datos { get; set; }

        public ucTransporteGuiasUnion()
        {
            InitializeComponent();
            this.Loaded += OnLoaded;
            this.Unloaded += OnUnloaded;
        }
        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            Datos?.ucLoaded();
        }
        private void OnUnloaded(object sender, RoutedEventArgs e)
        {
            Datos?.ucUnLoaded();
        }
        public void Resize(float width, float height)
        {
            if (Datos is osTransporteGuiasUnion datos)
                datos.AnchoRecto = PixelToMeter.Instance.calc.PixelsToMeters(width);
        }
        public void Move(float LeftPixels, float TopPixels)
        {
            if (Datos != null)
            {
                Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
                Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
            }
        }
        public void Rotate(float Angle)
        {
            if (Datos != null)
                if (Datos is osTransporteGuiasUnion datos)
                    datos.Angulo = Angle;
        }
        public void Highlight(bool State) { }
        public int ZIndex()
        {
            return 1;
        }

    }
}
