// EncoderMotorLinealViewModel.cs
using CommunityToolkit.Mvvm.ComponentModel;
using System.Windows.Media;
using System.ComponentModel;
using LibS7Adv;
using System.Diagnostics;
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
using CtrEditor.FuncionesBase;
using System.Windows;
using System.Windows.Controls;

namespace CtrEditor.ObjetosSim
{
    public partial class osEncoderMotorLineal : osBase, IosBase
    {
        public static string NombreCategoria() => "SensoresComandos";
        private osBase Motor = null;

        public static string NombreClase()
        {
            return "Encoder Motor Lineal";
        }

        private string nombre = NombreClase();

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

        [ObservableProperty]
        [property: Category("Apariencia")]
        [property: Description("Color visual del encoder")]
        [property: Name("Color")]
        private Brush color_oculto;

        [ObservableProperty]
        [property: Category("Información")]
        [property: Description("Velocidad actual del motor")]
        [property: Name("Velocidad Actual")]
        public float velocidadActual;

        [ObservableProperty]
        [property: Category("Encoder")]
        [property: Description("Pulsos por Hz por segundo (K)")]
        [property: Name("Pulsos por Hz")]
        public float pulsos_Por_Hz;

        [ObservableProperty]
        [property: Category("Información")]
        [property: Description("Valor actual del encoder")]
        [property: Name("Valor Actual")]
        public float valor_Actual;

        [ObservableProperty]
        [property: Category("Enlace PLC")]
        [property: Description("Motor enlazado al encoder")]
        [property: Name("Motor Enlazado")]
        [property: ItemsSource(typeof(osBaseItemsSource<osVMmotorSim>))]
        string id_Motor;

        [ObservableProperty]
        [property: Category("Enlace PLC")]
        [property: Description("Tag PLC para escribir valor del encoder")]
        [property: Name("Tag Valor Escritura")]
        string tag_Valor;

        [ObservableProperty]
        [property: Category("Enlace PLC")]
        [property: Description("Tag PLC para leer valor del encoder (tiene prioridad sobre motor)")]
        [property: Name("Tag Valor Lectura")]
        string tag_ReadValor;


        partial void OnId_MotorChanged(string value)
        {
            if (Motor != null)
                Motor.PropertyChanged -= OnMotorPropertyChanged;
            if (_mainViewModel != null && value != null && value.Length > 0)
            {
                Motor = (osVMmotorSim)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => (s is osVMmotorSim && s.Nombre == value), null);
                if (Motor != null)
                    Motor.PropertyChanged += OnMotorPropertyChanged;
            }
        }

        private void OnMotorPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(osVMmotorSim.Nombre))
            {
                Id_Motor = ((osVMmotorSim)sender).Nombre;
            }
        }

        public osEncoderMotorLineal()
        {
            Pulsos_Por_Hz = 3000; // Por defecto, un pulso por grado
            Color_oculto = Brushes.Gray;
        }

        public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
        {
            if (Tag_ReadValor != null && Tag_ReadValor.Length > 0)
            {
                // Bypass motor and read directly from tag
                var value = LeerDINTTag(tag_ReadValor);
                if (value != null)
                {
                    Valor_Actual = (int)value;
                    return;
                }
            }
            else if (Motor != null && Motor is osVMmotorSim motor)
            {
                VelocidadActual = motor.Velocidad;

                // Calcular giros por segundo basado en la velocidad actual
                float pulsosPorHz = (VelocidadActual * Pulsos_Por_Hz) / 100f;

                // Considerar el sentido de giro
                if (motor.Sentido_contrario)
                    pulsosPorHz = -pulsosPorHz;

                // Calcular incremento de pulsos para este ciclo
                float segundosTranscurridos = elapsedMilliseconds / 1000f;
                float incrementoPulsos = pulsosPorHz * segundosTranscurridos;

                // Actualizar valor del encoder
                if (motor.Motor_With_Encoder)
                    Valor_Actual = motor.Actual_Position;
                else
                    Valor_Actual = (Valor_Actual + incrementoPulsos);

                // Actualizar color basado en si está girando
                Color_oculto = Math.Abs(pulsosPorHz) > 0.01f ? Brushes.LightGreen : Brushes.Gray;

                // Escribir valor al PLC si hay tag configurado
                if (!string.IsNullOrEmpty(Tag_Valor))
                {
                    EscribirDINTTag(tag_Valor, (int)Valor_Actual);
                }
            }
        }

        public override void ucLoaded()
        {
            base.ucLoaded();
            OnId_MotorChanged(Id_Motor);
        }
    }

    public partial class ucEncoderMotorLineal : UserControl, IDataContainer
    {
        public osBase? Datos { get; set; }
        public int zIndex_fromFrames { get; set; }

        public ucEncoderMotorLineal()
        {
            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 Highlight(bool State) { }

        public ZIndexEnum ZIndex_Base()
        {
            return ZIndexEnum.Estaticos;
        }
    }
}