using Siemens.Simatic.Simulation.Runtime;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace CtrEditor.Siemens
{
    /// <summary>
    /// Interaction logic for PLCControl.xaml
    /// </summary>
    public class PLCViewModel : INotifyPropertyChanged
    {
        public readonly PLCModel PLCInterface;
        private readonly DispatcherTimer _timer;
        private string _cpuTime;
        private string _connectionStatus = "offline";
        private string _ip = "10.1.30.11";
        private string _name = "PLC";
        private string lastError;
        public bool IsConnected { get; private set; }

        public event PropertyChangedEventHandler PropertyChanged;

        public event EventHandler RefreshEvent;

        public PLCViewModel()
        {
            IsConnected = false;
            PLCInterface = new PLCModel();
            _timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(30) };
            _timer.Tick += (s, e) => Refresh();

            ConnectCommand = new RelayCommand(Connect, () => true);
            DisconnectCommand = new RelayCommand(Disconnect, () => true);
        }

        public string IP
        {
            get => _ip;
            set
            {
                _ip = value;
                OnPropertyChanged();
            }
        }

        public string Name
        {
            get => _name;
            set
            {
                _name = value;
                OnPropertyChanged();
            }
        }

        public string CpuTime
        {
            get => _cpuTime;
            set
            {
                _cpuTime = value;
                OnPropertyChanged();
            }
        }

        public string ConnectionStatus
        {
            get => _connectionStatus;
            set
            {
                _connectionStatus = value;
                OnPropertyChanged();
            }
        }

        [JsonIgnore]
        public ICommand ConnectCommand { get; }
        public ICommand DisconnectCommand { get; }
        public string LastError
        {
            get => lastError;
            set
            {
                lastError = value;
                OnPropertyChanged();
            }
        }

        public void Connect()
        {
            try
            {
                // Implementa la conexión utilizando PLCModel
                PLCInterface.Instance = SimulationRuntimeManager.CreateInterface(Name);
                PLCInterface.Instance.OnSoftwareConfigurationChanged += Instance_OnSoftwareConfigurationChanged;
                //_plcModel.Instance.CommunicationInterface = ECommunicationInterface.Softbus;

                if (PLCInterface.Instance != null)
                {
                    PLCInterface.UpdateTagList();
                    _timer.Start();
                    ConnectionStatus = "connected";
                    IsConnected = true;
                }
            } catch (Exception ex)
            {
                LastError = ex.Message;
                ConnectionStatus = "offline";
            }
        }

        private void Instance_OnSoftwareConfigurationChanged(IInstance instance, SOnSoftwareConfigChangedParameter event_param)
        {
            PLCInterface.UpdateTagList();
        }

        public void Disconnect()
        {
            IsConnected = false;
            _timer.Stop();
            ConnectionStatus = "offline";
            PLCInterface.Instance = null;
        }

        private void Refresh()
        {
            if (PLCInterface.Instance != null)
            {
                CpuTime = PLCInterface.LeerTagInt16("\"DB HMI\".CPU_Scan_Time")?.ToString() ?? "N/A";
                LastError = PLCInterface.LastError;

                // Disparar el evento RefreshEvent
                RefreshEvent?.Invoke(this, EventArgs.Empty);
            }
        }

        private void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public class PLCModel
    {
        public IInstance Instance { get; set; }
        public bool IsConfigured { get; set; }
        public string LastError { get; set; }

        public void UpdateTagList()
        {
            IsConfigured = false;
            try
            {
                Instance?.UpdateTagList(ETagListDetails.IO | ETagListDetails.DB, true);  // ETagListDetails.IO | ETagListDetails.DB
                IsConfigured = true;
            }
            catch (Exception ex)
            {
                LastError = ex.Message;
            }
        }

        public bool LeerSalidaBool(byte pByte, int pBit)
        {
            try
            {
                return Instance?.OutputArea.ReadBit(pByte, (byte)pBit) ?? false;
            }
            catch (Exception ex)
            {
                LastError = ex.Message;
                return false;
            }
        }

        public void EscribirInputBool(byte pByte, int pBit, bool pValue)
        {
            try
            {
                Instance?.InputArea.WriteBit(pByte, (byte)pBit, pValue);
            }
            catch (Exception ex)
            {
                LastError = ex.Message;
            }
        }
        public void EscribirTag(string pTag, SDataValue Value)
        {
            try
            {
                Instance?.Write(pTag, Value);
            }
            catch (Exception ex)
            {
                LastError = pTag + ":" + ex.Message;
            }
        }
        public SDataValue LeerTag(string pTag)
        {
            try
            {
                return Instance.Read(pTag);
            }
            catch (Exception ex)
            {
                LastError = pTag + ":" + ex.Message;
                return new SDataValue();
            }
        }
        public void EscribirTagBool(string pTag, bool pValue)
        {
            try
            {
                Instance?.WriteBool(pTag, pValue);
            }
            catch (Exception ex)
            {
                LastError = pTag + ":" + ex.Message;
            }
        }
        public void EscribirTagInt16(string pTag, int pValue)
        {
            try
            {
                Instance?.WriteInt16(pTag,(short) pValue);
            }
            catch (Exception ex)
            {
                LastError = pTag + ":" + ex.Message;
            }
        }

        public bool LeerTagBool(string pTag)
        {
            try
            {
                return Instance?.ReadBool(pTag) ?? false;
            }
            catch (Exception ex)
            {
                LastError = pTag + ":" + ex.Message;
                return false;
            }
        }

        public int? LeerTagInt16(string pTag)
        {
            try
            {
                return Instance?.ReadInt16(pTag);
            }
            catch (Exception ex)
            {
                LastError = pTag + ":" + ex.Message;
                return 0;
            }
        }
    }

    public partial class PLCControl : UserControl
    {
        public PLCControl()
        {
            InitializeComponent();
        }
    }
}
