const pairing = {
    pair: spi => {
        spi.Pair();
    },
    unpair: spi => {
        spi.Unpair();
        window.localStorage.removeItem('api_key');
        window.localStorage.removeItem('eftpos_address');
        window.localStorage.removeItem('posID');
        window.localStorage.removeItem('serial');
        window.localStorage.removeItem('test_mode');
        window.localStorage.removeItem('auto_address');
        window.localStorage.removeItem('use_secure_web_sockets');
        window.localStorage.removeItem('secrets');
    },
    pairingCancel: spi => {
        spi.PairingCancel();
    },
    pairingConfirmCode: spi => {
        spi.PairingConfirmCode();
    },
    setUseSecureWebSockets: (spi, isSecure) => {
        spi.SetSecureWebSockets(isSecure);
    },
    saveSettings: (spi, posId, testMode, serial, apiKey, secureWebSocket, autoAddress, eftpos) => {
        spi.SetAutoAddressResolution(autoAddress);
        spi.SetTestMode(testMode);
        spi.SetSecureWebSockets(secureWebSocket);
        spi.SetPosId(posId);
        spi.SetSerialNumber(serial);
        spi.SetDeviceApiKey(apiKey);
        spi.SetEftposAddress(eftpos);
        window.localStorage.setItem('api_key', apiKey);
        window.localStorage.setItem('eftpos_address', eftpos);
        window.localStorage.setItem('posID', posId);
        window.localStorage.setItem('serial', serial);
        window.localStorage.setItem('test_mode', testMode.toString());
        window.localStorage.setItem('auto_address', autoAddress.toString());
        window.localStorage.setItem('use_secure_web_sockets', secureWebSocket.toString());
    },
    handlePairingStatusUpdate: (pairingState, logger) => {
        logger.Info(`### PAIRING PROCESS UPDATE ###`);
        logger.Info(`# Process: ${pairingState.Message}`);
        logger.Info(`# Confirmation Code: ${pairingState.ConfirmationCode}`);
        logger.Info(`# Finished? ${pairingState.Finished}`);
        logger.Info(`# Successful? ${pairingState.Successful}`);
        logger.Info(`# Waiting Confirm from Eftpos? ${pairingState.AwaitingCheckFromEftpos}`);
        logger.Info(`# Waiting Confirm from POS? ${pairingState.AwaitingCheckFromPos}`);
    }
}

const purchase = {
    initiatePurchase: (spi, options, posRefId, purchaseAmount, tipAmount, cashoutAmount, surchargeAmount, promptForCashout) => {
        const res = spi.InitiatePurchaseTxV2(
            posRefId,
            purchaseAmount,
            tipAmount,
            cashoutAmount,
            promptForCashout,
            options,
            surchargeAmount
        );
        return res;
    },

    handleSuccessfulTransaction: (txStateResponse, logger) => {
        const purchaseResponse = new PurchaseResponse(txStateResponse);
        logger.Info(`# WOOHOO - WE GOT PAID!`);
        logger.Info(`# POS Reference: ${purchaseResponse.GetResponseValue('pos_ref_id')}`);
        logger.Info(`# Response: ${purchaseResponse.GetResponseText()}`);
        logger.Info(`# RRN: ${purchaseResponse.GetRRN()}`);
        logger.Info(`# Scheme: ${purchaseResponse.SchemeName}`);
        logger.Info(`# Customer Receipt:`);
        logger.Info(
            !purchaseResponse.WasCustomerReceiptPrinted()
                ? purchaseResponse.GetCustomerReceipt().trim()
                : `# PRINTED FROM EFTPOS`
        );
        logger.Info(`# PURCHASE: ${purchaseResponse.GetPurchaseAmount()}`);
        logger.Info(`# TIP: ${purchaseResponse.GetTipAmount()}`);
        logger.Info(`# SURCHARGE: ${purchaseResponse.GetSurchargeAmount()}`);
        logger.Info(`# CASHOUT: ${purchaseResponse.GetCashoutAmount()}`);
        logger.Info(`# BANKED NON-CASH AMOUNT: ${purchaseResponse.GetBankNonCashAmount()}`);
        logger.Info(`# BANKED CASH AMOUNT: ${purchaseResponse.GetBankCashAmount()}`);
    },
    handleFailedTransaction: (txStateResponse, logger) => {
        logger.Info(`# WE DID NOT GET PAID :(`);
        if (txStateResponse != null) {
            const purchaseResponse = new PurchaseResponse(txStateResponse);
            logger.Info(`# Error: ${txStateResponse.GetError()}`);
            logger.Info(`# Error Detail: ${txStateResponse.GetErrorDetail()}`);
            logger.Info(`# Response: ${purchaseResponse.GetResponseText()}`);
            logger.Info(`# RRN: ${purchaseResponse.GetRRN()}`);
            logger.Info(`# Scheme: ${purchaseResponse.SchemeName}`);
            logger.Info(`# Customer Receipt:`);
            logger.Info(
                !purchaseResponse.WasCustomerReceiptPrinted()
                    ? purchaseResponse.GetCustomerReceipt().trim()
                    : `# PRINTED FROM EFTPOS`
            );
        }
    },
    handleUnknownState: logger => {
        logger.Info(`# WE'RE NOT QUITE SURE WHETHER WE GOT PAID OR NOT :/`);
        logger.Info(`# CHECK THE LAST TRANSACTION ON THE EFTPOS ITSELF FROM THE APPROPRIATE MENU ITEM.`);
        logger.Info(`# IF YOU CONFIRM THAT THE CUSTOMER PAID, CLOSE THE ORDER.`);
        logger.Info(`# OTHERWISE, RETRY THE PAYMENT FROM SCRATCH.`);
    }
}

const refund = {
    initiateRefund(spi, posRefId, refundAmount, isMerchantPasswordSuppressed) {
        const res = spi.InitiateRefundTx(posRefId, refundAmount, isMerchantPasswordSuppressed);
        return res;
    },
    handleFailedTransaction(txStateResponse, logger) {
        logger.Info(`# REFUND FAILED!`);
        if (txStateResponse !== null) {
            const refundResponse = new RefundResponse(txStateResponse);

            logger.Info(`# Error: ${txStateResponse.GetError()}`);
            logger.Info(`# Error Detail: ${txStateResponse.GetErrorDetail()}`);
            logger.Info(`# Response: ${refundResponse.GetResponseText()}`);
            logger.Info(`# RRN: ${refundResponse.GetRRN()}`);
            logger.Info(`# Scheme: ${refundResponse.SchemeName}`);
            logger.Info(`# Customer Receipt:`);
            logger.Info(
                !refundResponse.WasCustomerReceiptPrinted() ? refundResponse.GetCustomerReceipt().trim() : `# PRINTED FROM EFTPOS`
            );
        }
    },
    handleSuccessfulTransaction: (txStateResponse, logger) => {
        const refundResponse = new RefundResponse(txStateResponse);
        logger.Info(`# REFUND GIVEN - OH WELL!`);
        logger.Info(`# POS Reference: ${refundResponse.GetResponseValue('pos_ref_id')}`);
        logger.Info(`# Response: ${refundResponse.GetResponseText()}`);
        logger.Info(`# RRN: ${refundResponse.GetRRN()}`);
        logger.Info(`# Scheme: ${refundResponse.SchemeName}`);
        logger.Info(`# Customer Receipt:`);
        logger.Info(
            !refundResponse.WasCustomerReceiptPrinted() ? refundResponse.GetCustomerReceipt().trim() : `# PRINTED FROM EFTPOS`
        );
        logger.Info(`# REFUNDED AMOUNT: ${refundResponse.GetRefundAmount()}`);
    },
    handleUnknownState(logger) {
        logger.Info(`# WE'RE NOT QUITE SURE WHETHER THE REFUND WENT THROUGH OR NOT :/`);
        logger.Info(`# CHECK THE LAST TRANSACTION ON THE EFTPOS ITSELF FROM THE APPROPRIATE MENU ITEM.`);
        logger.Info(`# YOU CAN THE TAKE THE APPROPRIATE ACTION.`);
    }
}

const cashout = {
    initiateCashout: (spi, cashoutAmount, surchargeAmount, logger) => {
        if (!(cashoutAmount > 0)) {
            console.log('Cashout amount must be greater than 0');
            return false;
        }
        const posRefId = `cashout-${new Date().toISOString()}`;
        const res = spi.InitiateCashoutOnlyTx(posRefId, cashoutAmount, surchargeAmount);
        logger.Info(
            res.Initiated
                ? '# Cashout Initiated. Will be updated with Progress.'
                : `# Could not initiate cashout: ${res.Message}. Please Retry.`
        );
    },
    handleSuccessfulTransaction: (txStateResponse, logger) => {
        const cashoutResponse = new CashoutOnlyResponse(txStateResponse);
        logger.Info(`# CASH-OUT SUCCESSFUL - HAND THEM THE CASH!`);
        logger.Info(`# POS Reference: ${cashoutResponse.GetResponseValue('pos_ref_id')}`);
        logger.Info(`# Response: ${cashoutResponse.GetResponseText()}`);
        logger.Info(`# RRN: ${cashoutResponse.GetRRN()}`);
        logger.Info(`# Scheme: ${cashoutResponse.SchemeName}`);
        logger.Info(`# Customer Receipt:`);
        if (cashoutResponse.WasCustomerReceiptPrinted()) {
            let receipt = cashoutResponse.GetCustomerReceipt().trim();
            //Do print receipt from POS integrated printer;
            logger.log(receipt);
        } else {
            logger.log(`# PRINTED FROM EFTPOS`)
        }
        logger.Info(`# CASHOUT: ${cashoutResponse.GetCashoutAmount()}`);
        logger.Info(`# BANKED NON-CASH AMOUNT: ${cashoutResponse.GetBankNonCashAmount()}`);
        logger.Info(`# BANKED CASH AMOUNT: ${cashoutResponse.GetBankCashAmount()}`);
        logger.Info(`# SURCHARGE: ${cashoutResponse.GetSurchargeAmount()}`);
    },
    handleFailedTransaction: (txStateResponse, logger) => {
        logger.Info(`# CASHOUT FAILED!`);
        if (txStateResponse != null) {
            const cashoutResponse = new CashoutOnlyResponse(txStateResponse);
            logger.Info(`# Error: ${txStateResponse.GetError()}`);
            logger.Info(`# Error Detail: ${txStateResponse.GetErrorDetail()}`);
            logger.Info(`# Response: ${cashoutResponse.GetResponseText()}`);
            logger.Info(`# RRN: ${cashoutResponse.GetRRN()}`);
            logger.Info(`# Scheme: ${cashoutResponse.SchemeName}`);
            logger.Info(`# Customer Receipt:`);
            logger.Info(cashoutResponse.GetCustomerReceipt());
        }
    },
    handleUnknownState() {
        logger.Info(`# WE'RE NOT QUITE SURE WHETHER THE CASHOUT WENT THROUGH OR NOT :/`);
        logger.Info(`# CHECK THE LAST TRANSACTION ON THE EFTPOS ITSELF FROM THE APPROPRIATE MENU ITEM.`);
        logger.Info(`# YOU CAN THE TAKE THE APPROPRIATE ACTION.`);
    }

}

const reversal = {
    initiateReversal: (spi, posRefId, logger) => {
        const res = spi.InitiateReversal(posRefId);
        logger.Info(
            res.Initiated
                ? '# Reversal Initiated. Will be updated with Progress.'
                : `# Could not initiate reversal: ${res.Message}. Please Retry.`
        );
    },
    handleFailedTransaction: (txStateResponse, logger) => {
        logger.Info(`# WE DID NOT GET TRANSACTION-REVERTED :(`);
        if (txStateResponse != null) {
            const reversalResponse = new ReversalResponse(txStateResponse);
            logger.Info(`# Error Detail: ${reversalResponse.GetErrorDetail()}`);
            logger.Info(`# Error Reason:: ${reversalResponse.GetErrorReason()}`);
            logger.Info(`# Success: ${reversalResponse.Success}`);
            logger.Info(`# PosRefID: ${reversalResponse.PosRefId}`);
        }
    },
    handleSuccessfulTransaction: (txStateResponse, logger) => {
        const reversalResponse = new ReversalResponse(txStateResponse);
        logger.Info(`# WOOHOO - REVERSAL SUCCESSFULL`);
        logger.Info(`# Success: ${reversalResponse.Success}`);
        logger.Info(`# PosRefID: ${reversalResponse.PosRefId}`);
    },
    handleUnknownState: logger => {
        logger.Info(`# WE'RE NOT QUITE SURE WHETHER THE REVERSAL WENT THROUGH OR NOT :/`);
        logger.Info(`# YOU CAN THE TAKE THE APPROPRIATE ACTION.`);
    }
}

const transaction = {
    // Handle generic transaction completion flows
    acceptSignature: (spi) => {
        spi.AcceptSignature(true);
    },
    declineSignature: (spi) => {
        spi.AcceptSignature(false);
    },
    cancelTransaction: (spi) => {
        spi.CancelTransaction();
    },
    submitAuthCode: (spi, authCode, logger) => {
        const res = spi.SubmitAuthCode(authCode);
        logger.Info(res.ValidFormat ? `# Auth code submitted` : `# Invalid Code Format. ${res.Message}. Try Again.`);
    },
    acknowledgeCompletion: (spi, printStatusAndActions, logger) => {
        spi.AckFlowEndedAndBackToIdle();
        logger.Clear();
        logger.Info('Select from the options below');
        printStatusAndActions();
    },
    acknowledgeCancellation: (spi, printStatusAndActions, logger) => {
        spi.AckFlowEndedAndBackToIdle();

        logger.Clear();
        logger.Info('Order Cancelled');
        printStatusAndActions();
    },
    printReceipt: (spi, header, footer, apiKey) => {
        const payload = Pos.sanitizePrintText(header + footer);
        spi.PrintReceipt(apiKey, payload);
    },
    // Handle the generic start of a transaction
    handleTransaction: (txState, logger) => {
        logger.Info('### TX PROCESS UPDATE ###');
        logger.Info(`# ${txState.DisplayMessage}`);
        logger.Info(`# PosRefId: ${txState.PosRefId}`);
        logger.Info(`# Type: ${txState.Type}`);
        logger.Info(`# Request Amount: $${(txState.AmountCents / 100.0).toFixed(2)}`);
        logger.Info(`# Waiting For Signature: ${txState.AwaitingSignatureCheck}`);
        logger.Info(`# Attempting to Cancel : ${txState.AttemptingToCancel}`);
        logger.Info(`# Finished: ${txState.Finished}`);
        logger.Info(`# Success: ${txState.Success}`);
    },
    // Recovery operations
    initiateRecovery: (spi, posRefId, logger) => {
        logger.Clear();
        const res = spi.InitiateRecovery(posRefId, TransactionType.Purchase);
        logger.Info(
            res.Initiated
                ? '# Recovery Initiated. Will be updated with Progress.'
                : `# Could not initiate recovery. ${res.Message}. Please Retry.`
        );
    },
    initiateGetTransaction: (spi, posRefId) => {
        const res = spi.InitiateGetTx(posRefId);
        return res;
    },
    handleGetTransaction: (txState, logger) => {
        console.log('handleGetTransaction');
        if (txState.Response !== null) {
            const purchaseResponse = new PurchaseResponse(txState.Response);
            logger.Info(`# Scheme: ${purchaseResponse.SchemeName}`);
            logger.Info(`# Response: ${purchaseResponse.GetResponseText()}`);
            logger.Info(`# RRN: ${purchaseResponse.GetRRN()}`);
            logger.Info(`# Error: ${txState.Response.GetError()}`);
            logger.Info(`# Customer Receipt:`);
            logger.Info(purchaseResponse.GetCustomerReceipt().trim());
        } else {
            // We did not even get a response, like in the case of a time-out.
            logger.Info('# Could Not Retrieve Transaction.');
        }
    },
    initiateGetLastTransaction: (spi, logger) => {
        const res = spi.InitiateGetLastTx();
        logger.Info(
            res.Initiated
                ? '# GLT Initiated. Will be updated with Progress.'
                : `# Could not initiate GLT: ${res.Message}. Please Retry.`
        );
    },
    handleGetLastTransaction: (spi, txState, posRefId, logger) => {
        if (txState.Response != null) {
            const gltResponse = new GetLastTransactionResponse(txState.Response);
            if (posRefId && posRefId.length > 1) {
                // User specified that he intended to retrieve a specific tx by pos_ref_id
                // This is how you can use a handy function to match it.
                const success = spi.GltMatch(gltResponse, posRefId);
                if (success === SuccessState.Unknown) {
                    logger.Info('# Did not retrieve Expected Transaction. Here is what we got:');
                } else {
                    logger.Info('# Tx Matched Expected Purchase Request.');
                }
            }

            const purchaseResponse = new PurchaseResponse(txState.Response);
            logger.Info(`# Scheme: ${purchaseResponse.SchemeName}`);
            logger.Info(`# Response: ${purchaseResponse.GetResponseText()}`);
            logger.Info(`# RRN: ${purchaseResponse.GetRRN()}`);
            logger.Info(`# Error: ${txState.Response.GetError()}`);
            logger.Info(`# Customer Receipt:`);
            logger.Info(purchaseResponse.GetCustomerReceipt().trim());
        } else {
            // We did not even get a response, like in the case of a time-out.
            logger.Info('# Could Not Retrieve Last Transaction.');
        }
    }
}

const setting = {
    setAutoAddressResolutionState: (
        spi,
        autoResolveEftposAddress,
        testMode,
        useSecureWebSockets
    ) => {
        spi.SetTestMode(testMode);
        spi.SetSecureWebSockets(useSecureWebSockets);
        spi.SetAutoAddressResolution(autoResolveEftposAddress);
    },
    setIsMerchantReceiptPrinted: (
        spi,
        isMerchantReceiptPrinted,
        printStatusAndActions,
        logger,
    ) => {
        spi.Config.PrintMerchantCopy = isMerchantReceiptPrinted;
        spi.AckFlowEndedAndBackToIdle();

        logger.Clear();
        printStatusAndActions();
    },
    setCustomReceiptStrings: (
        spi,
        options,
        customerReceiptHeader,
        customerReceiptFooter,
        merchantReceiptHeader,
        merchantReceiptFooter,
        printStatusAndActions,
        logger
    ) => {
        logger.Clear();
        spi._options = options;
        options.SetCustomerReceiptHeader(Pos.sanitizePrintText(customerReceiptHeader));
        options.SetCustomerReceiptFooter(Pos.sanitizePrintText(customerReceiptFooter));
        options.SetMerchantReceiptHeader(Pos.sanitizePrintText(merchantReceiptHeader));
        options.SetMerchantReceiptFooter(Pos.sanitizePrintText(merchantReceiptFooter));
        spi.AckFlowEndedAndBackToIdle();
        logger.Info('Receipt header / footer updated.');
        printStatusAndActions();
    },
    getTerminalStatus: spi => {
        spi.GetTerminalStatus();
    },
    onTxFlowStateChanged: (printStatusAndActions, logger) => {
        logger.Clear();
        printStatusAndActions();
        logger.Info('> ');
    },
    onPairingFlowStateChanged: (printStatusAndActions, logger) => {
        logger.Clear();
        printStatusAndActions();
        logger.Info('> ');
    },

    onSecretsChanged: (secrets) => {
        if (secrets != null) {
            console.info(`Have Secrets: Persist them Securely.`);
            window.localStorage.setItem('secrets', JSON.stringify(secrets));
        } else {
            console.info(`Have Lost the Secrets, i.e. Unpaired. Destroy the persisted secrets.`);
            window.localStorage.removeItem('secrets');
        }
    },

    saveSecrets: (encKey, hmacKey) => {
        console.log("saveSecrets:");
        console.log(encKey);
        console.log(hmacKey);
        if (encKey == null || encKey == '') {
            window.localStorage.removeItem('secrets');
        } else {
            var secrets = {};
            secrets.EncKey = encKey;
            secrets.HmacKey = hmacKey;
            console.log(secrets);
            console.log(JSON.stringify(secrets));
            window.localStorage.setItem('secrets', JSON.stringify(secrets));
        }
    },

    getSecrets: () => {
        const secretsString = localStorage.getItem('secrets') || '';
        try {
            const secrets = JSON.parse(secretsString);
            if (secrets) {
                return secrets;
            }
        } catch (error) {
            return "";
        }
    },


    onSpiStatusChanged: (printStatusAndActions, spiStatus, logger) => {
        logger.Clear();
        logger.Info(`# --> SPI Status Changed: ${spiStatus}`);
        printStatusAndActions();
    },
    handlePrintingResponse(spi, message, printStatusAndActions, logger) {
        logger.Clear();
        const printingResponse = new PrintingResponse(message);

        if (printingResponse.isSuccess()) {
            logger.Info('# --> Printing Response: Printing Receipt successful');
        } else {
            logger.Info(
                `# --> Printing Response:  Printing Receipt failed: reason = ${printingResponse.getErrorReason()}, detail = ${printingResponse.getErrorDetail()}`
            );
        }

        spi.AckFlowEndedAndBackToIdle();
        printStatusAndActions();
    },
    handleTerminalConfigurationResponse: (message, logger) => {
        const terminalConfigResponse = new TerminalConfigurationResponse(message);
        if (terminalConfigResponse.isSuccess()) {
            logger.Info('# Terminal Configuration Response #');
            logger.Info(`# Comms Method: ${terminalConfigResponse.GetCommsSelected()}`);
            logger.Info(`# MerchantId: ${terminalConfigResponse.GetMerchantId()}`);
            logger.Info(`# PA Version: ${terminalConfigResponse.GetPAVersion()}`);
            logger.Info(`# Payment Interface Version: ${terminalConfigResponse.GetPaymentInterfaceVersion()}`);
            logger.Info(`# Plugin Version: ${terminalConfigResponse.GetPluginVersion()}`);
            logger.Info(`# Serial Number: ${terminalConfigResponse.GetSerialNumber()}`);
            logger.Info(`# TerminalId: ${terminalConfigResponse.GetTerminalId()}`);
            logger.Info(`# Terminal Model: ${terminalConfigResponse.GetTerminalModel()}`);
        }
    },
    handleTerminalStatusResponse: (spi, message, printStatusAndActions, logger) => {
        logger.Clear();
        const terminalStatusResponse = new TerminalStatusResponse(message);
        logger.Info('# Terminal Status Response #');
        logger.Info(`# Status: ${terminalStatusResponse.GetStatus()}`);
        logger.Info(`# Battery Level: ${terminalStatusResponse.GetBatteryLevel()}%`);
        logger.Info(`# Charging: ${terminalStatusResponse.IsCharging()}`);
        spi.AckFlowEndedAndBackToIdle();
        printStatusAndActions();
    },
    handleTransactionUpdateMessage: (message, logger) => {
        const txnUpdateMessage = new TransactionUpdate(message);
        logger.Info(`${txnUpdateMessage.GetDisplayMessageText()}`);
    },
    handleBatteryLevelChanged: (spi, message, printStatusAndActions, logger) => {
        logger.clear();
        const terminalBattery = new TerminalBattery(message);
        logger.Info('# Battery Level Changed #');
        logger.Info(`# Battery Level: ${terminalBattery.BatteryLevel}%`);
        spi.AckFlowEndedAndBackToIdle();
        printStatusAndActions();
    },
    isUnknownStatus: spi => {
        if (spi.CurrentFlow === SpiFlow.Transaction) {
            if (spi.CurrentTxFlowState.Finished && spi.CurrentTxFlowState.Success === SuccessState.Unknown) {
                return true;
            }
        }
        return false;
    }
}

const settlement = {
    initiateSettlement: (spi, logger) => {
        const res = spi.InitiateSettleTx(RequestIdHelper.Id('settle'));
        return res;
    },
    handleFailedTransaction: (txStateResponse, logger) => {
        logger.Info(`# SETTLEMENT FAILED!`);
        if (txStateResponse != null) {
            const settlementResponse = new Settlement(txStateResponse);
            logger.Info(`# Response: ${settlementResponse.GetResponseText()}`);
            logger.Info(`# Error: ${txStateResponse.GetError()}`);
            logger.Info(`# Merchant Receipt:`);
            logger.Info(settlementResponse.GetReceipt());
        }
    },
    handleSuccessfulTransaction: (txStateResponse, logger) => {
        logger.Info(`# SETTLEMENT SUCCESSFUL!`);
        if (txStateResponse != null) {
            const settlementResponse = new Settlement(txStateResponse);
            logger.Info(`# Response: ${settlementResponse.GetResponseText()}`);
            logger.Info(`# Merchant Receipt:`);
            //Print Receipt
            logger.Info(settlementResponse.GetReceipt().trim());
            logger.Info(`# Period Start: ${settlementResponse.GetPeriodStartTime()}`);
            logger.Info(`# Period End: ${settlementResponse.GetPeriodEndTime()}`);
            logger.Info(`# Settlement Time: ${settlementResponse.GetTriggeredTime()}`);
            logger.Info(`# Transaction Range: ${settlementResponse.GetTransactionRange()}`);
            logger.Info(`# Terminal Id: ${settlementResponse.GetTerminalId()}`);
            logger.Info(`# Total TX Count: ${settlementResponse.GetTotalCount()}`);
            logger.Info(`# Total TX Value: $${(settlementResponse.GetTotalValue() / 100.0).toFixed(2)}`);
            logger.Info(`# By Acquirer TX Count: ${settlementResponse.GetSettleByAcquirerCount()}`);
            logger.Info(`# By Acquirer TX Value: $${(settlementResponse.GetSettleByAcquirerValue() / 100.0).toFixed(2)}`);
            logger.Info(`# SCHEME SETTLEMENTS:`);
            const schemes = settlementResponse.GetSchemeSettlementEntries();
            schemes.forEach(s => {
                logger.Info(`# ${JSON.stringify(schemes[s])}`);
            });
        }
    },
    handleUnknownState: (logger) => {
        logger.Info(`# SETTLEMENT ENQUIRY RESULT UNKNOWN!`);
    }
}

const settlementEnquiry = {
    initiateSettlementEnquiry: (spi, logger) => {
        const res = spi.InitiateSettlementEnquiry(RequestIdHelper.Id('stlenq'));
        logger.Info(
            res.Initiated
                ? '# Settle enquiry Initiated. Will be updated with Progress.'
                : `# Could not initiate settle enquiry: ${res.Message}. Please Retry.`
        );
    },
    handleFailedTransaction: (txStateResponse, logger) => {
        logger.Info(`# SETTLEMENT ENQUIRY FAILED!`);
        if (txStateResponse != null) {
            const settleResponse = new Settlement(txStateResponse);
            logger.Info(`# Response: ${settleResponse.GetResponseText()}`);
            logger.Info(`# Error: ${txStateResponse.GetError()}`);
            logger.Info(`# Merchant Receipt:`);
            logger.Info(settleResponse.GetReceipt());
        }
    },
    handleSuccessfulTransaction: (txStateResponse, logger) => {
        logger.Info(`# SETTLEMENT ENQUIRY SUCCESSFUL!`);
        if (txStateResponse != null) {
            const settleResponse = new Settlement(txStateResponse);
            logger.Info(`# Response: ${settleResponse.GetResponseText()}`);
            logger.Info(`# Merchant Receipt:`);
            //Print receipt
            logger.Info(settleResponse.GetReceipt().trim());
            logger.Info(`# Period Start: ${settleResponse.GetPeriodStartTime()}`);
            logger.Info(`# Period End: ${settleResponse.GetPeriodEndTime()}`);
            logger.Info(`# Settlement Time: ${settleResponse.GetTriggeredTime()}`);
            logger.Info(`# Transaction Range: ${settleResponse.GetTransactionRange()}`);
            logger.Info(`# Terminal Id: ${settleResponse.GetTerminalId()}`);
            logger.Info(`# Total TX Count: ${settleResponse.GetTotalCount()}`);
            logger.Info(`# Total TX Value: $${(settleResponse.GetTotalValue() / 100.0).toFixed(2)}`);
            logger.Info(`# By Acquirer TX Count: ${settleResponse.GetSettleByAcquirerCount()}`);
            logger.Info(`# By Acquirer TX Value: $${(settleResponse.GetSettleByAcquirerValue() / 100.0).toFixed(2)}`);
            logger.Info(`# SCHEME SETTLEMENTS:`);
            const schemes = settleResponse.GetSchemeSettlementEntries();
            schemes.forEach(s => {
                logger.Info(`# ${JSON.stringify(schemes[s])}`);
            });
        }
    },
    handleUnknownState: logger => {
        logger.Info(`# SETTLEMENT ENQUIRY RESULT UNKNOWN!`);
    }
}

const utility = {
    // Cleans RTF strings so that the terminal will accept them
    sanitizePrintText: content => {
        let sanitizedText = content.replace('\\emphasis', 'emphasis');
        sanitizedText = sanitizedText.replace('\\clear', 'clear');
        return sanitizedText.replace('\r\n', '\n');
    },
    processCompletedEvent: (eventType, transactionState, logger) => {
        const transactionStateMap = {
            [SuccessState.Failed]: eventType.handleFailedTransaction,
            [SuccessState.Success]: eventType.handleSuccessfulTransaction,
            [SuccessState.Unknown]: eventType.handleUnknownState,
        };
        const trasactionStateHandler = transactionStateMap[transactionState.Success];
        if (!trasactionStateHandler) {
            throw new Error('Unknown transaction state');
        }
        trasactionStateHandler(transactionState.Response, logger);
    },
    isTransactionInquiry: transactionType => [TransactionType.GetTransaction, TransactionType.GetLastTransaction].includes(transactionType)
}

const helpers = {
    pairing,
    purchase,
    refund,
    cashout,
    reversal,
    transaction,
    setting,
    settlement,
    settlementEnquiry,
    //string
}