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

namespace WinRT.BxlComponent.Plugin.BxlMpXamarinSDK
{
    internal partial class MPosControllerScannerImplementation : MPosControllerScanner
    {
        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();
    }

    internal partial class MPosControllerScannerImplementation : MPosControllerScanner
    {
        public MPosControllerScannerImplementation(int deviceType, int deviceId)
        {
            MPosDebug.WriteLine("ScannerImplementation Constructor : START");
            DeviceID = deviceId;
            DeviceType = (MPosDeviceType)deviceType;
            MPosDebug.WriteLine("ScannerImplementation Constructor : DeviceID = " + DeviceID);
            MPosDebug.WriteLine("ScannerImplementation Constructor : DeviceType = " + DeviceType);
            MPosDebug.WriteLine("ScannerImplementation Constructor : END");
        }
        public async Task<int> openService(uint timeout = 5 /*second*/)
        {
            if (IsOpen)
            {
                MPosDebug.WriteLine("ScannerImplementation openService : MPOS_ALREADY_OPEN");
                MPosDebug.WriteLine("ScannerImplementation 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("ScannerImplementation openService : START");
            MPosDebug.WriteLine("ScannerImplementation openService : ConnectionString = " + _ConnectionString);
            MPosDebug.WriteLine("ScannerImplementation openService : CommandMode = " + CommandMode.ToString());

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

            if (_MPosConnection == null)
            {
                MPosDebug.WriteLine("ScannerImplementation openService : MPosConnectionBuilder.Current.Build failed.");
                MPosDebug.WriteLine("ScannerImplementation 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("ScannerImplementation 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("ScannerImplementation openService : END");
            return result;
        }
        public async Task<int> closeService(uint closeTimeout = 0 /*second*/)
        {
            MPosDebug.WriteLine("ScannerImplementation 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("ScannerImplementation closeService : END");
            return (int)MPosResult.MPOS_SUCCESS;
        }
        public bool isOpen()
        {
            return IsOpen;
        }
        public int selectCommandMode(int commandMode)
        {
            MPosDebug.WriteLine("ScannerImplementation selectCommandMode : START");
            MPosDebug.WriteLine("ScannerImplementation selectCommandMode : commandMode = " + commandMode);

            CommandMode = (MPosCommandMode)commandMode;

            MPosDebug.WriteLine("ScannerImplementation selectCommandMode : END");
            return (int)MPosResult.MPOS_SUCCESS;
        }
        public int selectInterface(int interfaceType, string address)
        {
            MPosDebug.WriteLine("ScannerImplementation selectInterface : START");
            MPosDebug.WriteLine("ScannerImplementation 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("ScannerImplementation selectInterface : _ConnectionString = " + _ConnectionString);
                MPosDebug.WriteLine("ScannerImplementation selectInterface : END");
                return (int)MPosResult.MPOS_SUCCESS;
            }

            MPosDebug.WriteLine("ScannerImplementation selectInterface : MPOS_FAIL_INVALID_PARAMETER");
            MPosDebug.WriteLine("ScannerImplementation 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)
        {
            return (int)MPosResult.MPOS_FAIL_NOT_SUPPORT;
        }
    }
    internal partial class MPosControllerScannerImplementation : MPosControllerScanner
    {
        public event Action<byte[]> dataEvent;
        public event Action<int, byte[]> dataEvent2;
        public event Action<uint> statusUpdateEvent;
        private async void onConnectedEvent()
        {
            MPosDebug.WriteLine("ScannerImplementation 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("ScannerImplementation onConnectedEvent : statusUpdateEvent is null");
            MPosDebug.WriteLine("ScannerImplementation onConnectedEvent : fireStatusUpdateEvent");
            statusUpdateEvent?.Invoke((uint)MPosPrinterStatus.MPOS_STATUS_NORMAL);
        }
        private void onDisconnectedEvent()
        {
            MPosDebug.WriteLine("ScannerImplementation onDisconnectedEvent");
            if (statusUpdateEvent == null)
                MPosDebug.WriteLine("ScannerImplementation onDisconnectedEvent : statusUpdateEvent is null");
            MPosDebug.WriteLine("ScannerImplementation onDisconnectedEvent : fireStatusUpdateEvent");
            statusUpdateEvent?.Invoke((uint)MPosPrinterStatus.MPOS_STATUS_PRINTER_ERROR);
        }
        private void onDataReadEvent(int deviceId, byte[] data)
        {
            MPosDebug.WriteLine("ScannerImplementation 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("ScannerImplementation 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);
        }
    }
}
