// EncoderMotorViewModel.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 osEncoderMotor : osBase, IosBase
    {
        public static string NombreCategoria() => "SensoresComandos";
        private osBase Motor = null;

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

        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 vuelta del encoder")]
        [property: Name("Pulsos por Vuelta")]
        public float pulsos_Por_Vuelta;

        [ObservableProperty]
        [property: Category("Encoder")]
        [property: Description("Ratio de giros por 50Hz")]
        [property: Name("Ratio Giros 50Hz")]
        public float ratio_Giros_50hz;

        [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 valor del encoder")]
        [property: Name("Tag Valor")]
        string tag_Valor;

        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 osEncoderMotor()
        {
            Pulsos_Por_Vuelta = 360; // Por defecto, un pulso por grado
            Ratio_Giros_50hz = 1;    // Por defecto, 1 giro por cada 50Hz
            Color_oculto = Brushes.Gray;
        }

        public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
        {
            if (Motor != null && Motor is osVMmotorSim motor)
            {
                VelocidadActual = motor.Velocidad;

                // Calcular giros por segundo basado en la velocidad actual
                // velocidad * ratio_giros_50hz / 100 nos da los giros por segundo a esa velocidad
                float girosPorSegundo = (VelocidadActual * Ratio_Giros_50hz) / 100f;

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

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

                // Actualizar valor del encoder
                Valor_Actual = (Valor_Actual + incrementoPulsos) % Pulsos_Por_Vuelta;
                if (Valor_Actual < 0) Valor_Actual += Pulsos_Por_Vuelta;

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

                // Escribir valor al PLC si hay tag configurado
                if (!string.IsNullOrEmpty(Tag_Valor))
                {
                    EscribirWordTagScaled(Tag_Valor, Valor_Actual, 0, Pulsos_Por_Vuelta, 0, 27648);
                }
            }
        }

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

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

        public ucEncoderMotor()
        {
            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;
        }
    }
}