using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using PLCIOPointTool.Services;
using TwinCAT;
using TwinCAT.Ads;

namespace PLCIOPointTool.ViewModels;

public enum DataType
{
    Bool,
    INT16, //short
    UINT16,//unsigned short
    INT32,
    FLOAT,
    DOUBLE
}

public partial class WorkAreaViewModel : ObservableObject, IDisposable
{
    private readonly ILogService _logService;
    private readonly IClientService _clientService;

    private bool disposedValue;

    #region ObservableProperty
    [ObservableProperty]
    private bool _isConnected = false;

    [ObservableProperty]
    private string _readSymbolName = string.Empty;

    [ObservableProperty]
    private string _readValue = string.Empty;

    [ObservableProperty]
    private string _readValueType = string.Empty;

    [ObservableProperty]
    private string _writeSymbolName = string.Empty;

    [ObservableProperty]
    private string _writeValue = string.Empty;

    [ObservableProperty]
    private DataType[] _dataTypes = Enum.GetValues<DataType>();

    [ObservableProperty]
    private int _dataTypeId = -1;
    #endregion

    public WorkAreaViewModel(ILogService logService, IClientService clientService)
    {
        _logService = logService;
        _clientService = clientService;
        _clientService.ConnectionStateChanged += OnConnectionStateChanged;
    }

    [RelayCommand]
    private void Read()
    {
        Task.Run(async () =>
        {
            var value = await _clientService.ReadValue(ReadSymbolName);
            if (value != null)
            {
                ReadValue = value.ToString()!;
                ReadValueType = value.GetType().Name;
            }
        });
    }

    [RelayCommand]
    private void Write()
    {
        Task.Run(async () =>
        {
            try
            {
                if (DataTypeId < 0 || string.IsNullOrWhiteSpace(WriteValue))
                {
                    _logService.Warning($"Input parameters before writing");
                    return;
                }

                var dataType = (DataType)DataTypeId;
                object value = dataType switch
                {
                    DataType.Bool => bool.Parse(WriteValue),
                    DataType.INT16 => short.Parse(WriteValue),
                    DataType.UINT16 => ushort.Parse(WriteValue),
                    DataType.INT32 => int.Parse(WriteValue),
                    DataType.FLOAT => float.Parse(WriteValue),
                    DataType.DOUBLE => double.Parse(WriteValue),
                    _ => throw new NotImplementedException()
                };
                await _clientService.WriteValue(WriteSymbolName, value);
            }
            catch (Exception ex)
            {
                _logService.Error($"Got an exception {ex}");
            }

        });
    }



    private void OnConnectionStateChanged(object? sender, ConnectionState e)
    {
        IsConnected = e switch
        {
            ConnectionState.Connected => true,
            ConnectionState.Disconnected => false,
            _ => throw new NotImplementedException()
        };
    }


    #region Dispose
    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                // TODO: dispose managed state (managed objects)
            }

            // TODO: free unmanaged resources (unmanaged objects) and override finalizer
            // TODO: set large fields to null
            disposedValue = true;
        }
    }

    // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
    // ~WorkAreaViewModel()
    // {
    //     // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
    //     Dispose(disposing: false);
    // }

    public void Dispose()
    {
        // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
        Dispose(disposing: true);
        GC.SuppressFinalize(this);
    }
    #endregion
}
