using System;
using System.Linq;
using System.Threading.Tasks;
using WinRT.BxlComponent.Plugin.BxlMpXamarinSDK;
using WinRT.BxlComponent.Plugin.BxlMpXamarinSDK.Abstractions;

namespace Plugin.BxlMAUISDK.PlatformImplementations
{
    partial class MPosControllerHIDImplementation : MPosControllerHID
    {
        public int DeviceID { get; private set; }
        public MPosDeviceType DeviceType { get; private set; }
        public MPosInterfaceType InterfaceType { get; private set; } = MPosInterfaceType.MPOS_INTERFACE_BLUETOOTH;
        public bool IsOpen { get; private set; } = false;
        public MPosCommandMode CommandMode { get; private set; } = MPosCommandMode.MPOS_COMMAND_MODE_BGATE;
        public IMPosConnection _MPosConnection { get; private set; } = null;
        public string _ConnectionString { get; private set; }

        //private MPosDeviceDataProcessor _DeviceDataProcessor = new MPosDeviceDataProcessor();
    }

    partial class MPosControllerHIDImplementation : MPosControllerHID
    {
        public MPosControllerHIDImplementation(int deviceType, int deviceId)
        {
            MPosDebug.WriteLine("HIDImplementation Constructor : START");
            DeviceID = deviceId;
            DeviceType = (MPosDeviceType)deviceType;
            MPosDebug.WriteLine("HIDImplementation Constructor : DeviceID = " + DeviceID);
            MPosDebug.WriteLine("HIDImplementation Constructor : DeviceType = " + DeviceType);
            MPosDebug.WriteLine("HIDImplementation Constructor : END");
        }
        public async Task<int> openService(uint timeout = 5 /*second*/)
        {
            if (IsOpen)
            {
                MPosDebug.WriteLine("HIDImplementation openService : MPOS_ALREADY_OPEN");
                MPosDebug.WriteLine("HIDImplementation openService : END");
                return (int)MPosResult.MPOS_ALREADY_OPEN;
            }

            return await openService((uint)DeviceID, timeout);
        }
        public async Task<int> openService(uint deviceId = 0, uint timeout = 5 /*second*/)
        {
            int result = (int)MPosResult.MPOS_SUCCESS;
            MPosDebug.WriteLine("HIDImplementation openService : START");
            MPosDebug.WriteLine("HIDImplementation openService : ConnectionString = " + _ConnectionString);
            MPosDebug.WriteLine("HIDImplementation openService : CommandMode = " + CommandMode.ToString());

            _MPosConnection = MPosConnectionBuilderImplementation.Build(InterfaceType, _ConnectionString, (int)CommandMode);

            if (_MPosConnection == null)
            {
                MPosDebug.WriteLine("HIDImplementation openService : MPosConnectionBuilder.Current.Build failed.");
                MPosDebug.WriteLine("HIDImplementation openService : END");
                return (int)MPosResult.MPOS_FAIL_NOT_CONNECT;
            }

            try
            {
                //_DeviceDataProcessor.initDataStream();
                _MPosConnection.addDataReadEvent(onDataReadEvent);
                _MPosConnection.addDisconnectedEvent(onDisconnectedEvent);
                _MPosConnection.addConnectedEvent(onConnectedEvent);
                _MPosConnection.addDeviceListUpdateEvent(onDeviceListUpdateEvent);

                if (await _MPosConnection.openAsync(DeviceType, timeout))
                {
                    IsOpen = true;
                    DeviceID = (int)deviceId;

                    //DeviceID를 받아온 이후에 다시 한 번 OnConnectedEvent를 발생시킨다.
                    onConnectedEvent();
                }
            }
            catch (Exception ex)
            {
                MPosDebug.WriteLine("HIDImplementation openService : ex.Message = " + ex.Message);
                IsOpen = false;
            }

            if (!IsOpen)
            {
                await _MPosConnection.closeAsync();
                _MPosConnection = null;
                result = (int)MPosResult.MPOS_FAIL_NOT_CONNECT;
            }
            else
            {
                result = (int)MPosResult.MPOS_SUCCESS;
            }

            if (CommandMode == MPosCommandMode.MPOS_COMMAND_MODE_BGATE && result == (int)MPosResult.MPOS_SUCCESS)
            {
                MPosConnectionBuilderImplementation.AddDevice(DeviceID);
            }

            MPosDebug.WriteLine("HIDImplementation openService : END");
            return result;
        }
        public async Task<int> closeService(uint closeTimeout = 0 /*second*/)
        {
            MPosDebug.WriteLine("HIDImplementation closeService : START");
            if (CommandMode == MPosCommandMode.MPOS_COMMAND_MODE_BGATE)
                MPosConnectionBuilderImplementation.RemoveDevice(DeviceID);
            IsOpen = false;
            statusUpdateEvent = null;
            dataEvent = null;
            //_DeviceDataProcessor.clearDataStream();

            if (_MPosConnection != null)
            {
                _MPosConnection.removeDataReadEvent(onDataReadEvent);
                _MPosConnection.removeDisconnectedEvent(onDisconnectedEvent);
                _MPosConnection.removeConnectedEvent(onConnectedEvent);
                _MPosConnection.removeDeviceListUpdateEvent(onDeviceListUpdateEvent);
                await _MPosConnection.closeAsync(closeTimeout);
                _MPosConnection = null;
            }

            MPosDebug.WriteLine("HIDImplementation closeService : END");
            return (int)MPosResult.MPOS_SUCCESS;
        }
        public bool isOpen()
        {
            return IsOpen;
        }
        public int selectCommandMode(int commandMode)
        {
            MPosDebug.WriteLine("HIDImplementation selectCommandMode : START");
            MPosDebug.WriteLine("HIDImplementation selectCommandMode : commandMode = " + commandMode);

            CommandMode = (MPosCommandMode)commandMode;

            MPosDebug.WriteLine("HIDImplementation selectCommandMode : END");
            return (int)MPosResult.MPOS_SUCCESS;
        }
        public int selectInterface(int interfaceType, string address)
        {
            MPosDebug.WriteLine("HIDImplementation selectInterface : START");
            MPosDebug.WriteLine("HIDImplementation selectInterface : interfaceType = " + interfaceType + " address = " + address);

            bool isMember = Enum.GetValues(typeof(MPosInterfaceType)).Cast<int>().Any(x => x == (int)interfaceType);

            if (isMember)
            {
                InterfaceType = (MPosInterfaceType)interfaceType;
                _ConnectionString = address;
                MPosDebug.WriteLine("HIDImplementation selectInterface : _ConnectionString = " + _ConnectionString);
                MPosDebug.WriteLine("HIDImplementation selectInterface : END");
                return (int)MPosResult.MPOS_SUCCESS;
            }

            MPosDebug.WriteLine("HIDImplementation selectInterface : MPOS_FAIL_INVALID_PARAMETER");
            MPosDebug.WriteLine("HIDImplementation selectInterface : END");
            return (int)MPosResult.MPOS_FAIL_INVALID_PARAMETER;
        }
        public async Task<int> setTransaction(int transactionMode)
        {
            return (int)MPosResult.MPOS_FAIL_NOT_SUPPORT;
        }
        public async Task<int> directIO(byte[] data)
        {
            MPosDebug.WriteLine("HIDImplementation directIO : START");

            if (IsOpen == false || _MPosConnection == null)
            {
                MPosDebug.WriteLine("HIDImplementation directIO : MPOS_FAIL_NO_OPEN");
                MPosDebug.WriteLine("HIDImplementation directIO : END");
                return (int)MPosResult.MPOS_FAIL_NO_OPEN;
            }

            int writtenBytes = 0;
            if (data != null)
            {
                MPosDebug.WriteLine("HIDImplementation directIO : data.Length = " + data.Length);
                writtenBytes = await _MPosConnection.writeAsync(DeviceID, data, false, true);
                MPosDebug.WriteLine("HIDImplementation directIO : written bytes = " + writtenBytes);
            }

            MPosDebug.WriteLine("HIDImplementation directIO : END");
            if (writtenBytes <= 0)
                return (int)MPosResult.MPOS_FAIL;
            return (int)MPosResult.MPOS_SUCCESS;
        }
    }
    partial class MPosControllerHIDImplementation : MPosControllerHID
    {
        public event Action<byte[]> dataEvent;
        public event Action<int, byte[]> dataEvent2;
        public event Action<uint> statusUpdateEvent;
        private async void onConnectedEvent()
        {
            MPosDebug.WriteLine("HIDImplementation onConnectedEvent");
            byte[] commandToWrite = null;
            if (CommandMode == MPosCommandMode.MPOS_COMMAND_MODE_BGATE)
                commandToWrite = MPosBgateCmdBuilder.getReadModeCmd((uint)DeviceID, BgateDeviceReadMode.AUTO_ENABLE);
            else if (DeviceID < 0xff)
                commandToWrite = new byte[] { 0x08, 0x7e, 0x52, (byte)DeviceID, 0x01 };
            await _MPosConnection.writeAsync(DeviceID, commandToWrite, false, false);

            if (statusUpdateEvent == null)
                MPosDebug.WriteLine("HIDImplementation onConnectedEvent : statusUpdateEvent is null");
            MPosDebug.WriteLine("HIDImplementation onConnectedEvent : fireStatusUpdateEvent");
            statusUpdateEvent?.Invoke((uint)MPosPrinterStatus.MPOS_STATUS_NORMAL);
        }
        private void onDisconnectedEvent()
        {
            MPosDebug.WriteLine("HIDImplementation onDisconnectedEvent");
            if (statusUpdateEvent == null)
                MPosDebug.WriteLine("HIDImplementation onDisconnectedEvent : statusUpdateEvent is null");
            MPosDebug.WriteLine("HIDImplementation onDisconnectedEvent : fireStatusUpdateEvent");
            statusUpdateEvent?.Invoke((uint)MPosPrinterStatus.MPOS_STATUS_PRINTER_ERROR);
        }
        private void onDataReadEvent(int deviceId, byte[] data)
        {
            MPosDebug.WriteLine("HIDImplementation onDataReadEvent : deviceId = " + deviceId + ", DeviceID = " + DeviceID);
            if (data == null)
                return;
            if (CommandMode == MPosCommandMode.MPOS_COMMAND_MODE_BGATE)
            {
                if (deviceId != DeviceID)
                    return;
            }
            //DeviceDataProcessor.writeData(data);
            if (dataEvent2 == null)
                MPosDebug.WriteLine("HIDImplementation onDataReadEvent : dataEvent is null");
            dataEvent2?.Invoke(deviceId, data);
        }
        private void onDeviceListUpdateEvent(int[] devList)
        {
            if (devList.Any(x => x == DeviceID) == false)
            {
                statusUpdateEvent?.Invoke((uint)MPosPrinterStatus.MPOS_STATUS_PRINTER_ERROR);
                return;
            }
            statusUpdateEvent?.Invoke((uint)MPosPrinterStatus.MPOS_STATUS_NORMAL);
        }
    }
}
