// Terminal listener logging request outcome
class Listener extends timapi.DefaultTerminalListener {
    // Create listener
    constructor() {
        super();
    }

    // Terminal status changed
    terminalStatusChanged(terminal) {
        let status = terminal.getTerminalStatus();

        let tagDisplay = document.getElementById('display');
        tagDisplay.innerHTML = '';
        status.displayContent.forEach(function (each) {
            let tagDiv = document.createElement('div');
            tagDiv.innerHTML = escapeHtml(each);
            tagDisplay.appendChild(tagDiv);
        });

        document.getElementById('statusConnection').innerHTML = status.connectionStatus ?
            escapeHtml(humanReadableConstName(status.connectionStatus.name)) : '-';
        document.getElementById('statusManagement').innerHTML = status.managementStatus ?
            escapeHtml(humanReadableConstName(status.managementStatus.name)) : '-';
        document.getElementById('statusCardReader').innerHTML = status.cardReaderStatus ?
            escapeHtml(humanReadableConstName(status.cardReaderStatus.name)) : '-';
        document.getElementById('statusTransaction').innerHTML = status.transactionStatus ?
            escapeHtml(humanReadableConstName(status.transactionStatus.name)) : '-';
        document.getElementById('statusSleepMode').innerHTML = status.sleepModeStatus ?
            escapeHtml(humanReadableConstName(status.sleepModeStatus.name)) : '-';

        let flags = Array();
        if (status.swUpdateAvailable) {
            flags.push('swUpdateAvailable');
        }
        if (status.hasReceiptInformation) {
            flags.push('hasReceiptInformation');
        }
        document.getElementById('statusFlags').innerHTML = flags ? escapeHtml(flags.join(', ')) : '-';

        if (status.connectionStatus == timapi.constants.ConnectionStatus.disconnected) {
            ecr.connected = false;
            ecr.loggedin = false;
            ecr.activated = false;
        } else {
            ecr.connected = true;
            if (status.connectionStatus == timapi.constants.ConnectionStatus.loggedIn) {
                ecr.loggedin = true;
                if (status.managementStatus == timapi.constants.ManagementStatus.closed) {
                    ecr.activated = false;
                } else {
                    ecr.activated = true;
                }
            } else {
                ecr.loggedin = false;
            }
        }
    }

    activateCompleted(event, data) {
        let message = this.getEventCompletedString("Activate Completed", event);
        if (data) {
            message = message.concat(
                ` actSeqCounter = ${event.terminal.getActSeqCounter()}`
            );
            message = message.concat(` data = ${dumpValue(data)}`);
        }
        timapi.log(message);
        if (!event.exception) {
            ecr.activated = true;
            if (ecr.initialConnection) {
                ecr.actionInitConnection();
            }
        }

        super.activateCompleted(event, data);
    }

    applicationInformationCompleted(event) {
        let message =
            this.getEventCompletedString("Application Info Completed", event) +
            ` brands=${dumpValue(event.terminal.getBrands())}`;
        timapi.log(message);
        super.applicationInformationCompleted(event);
    }

    balanceCompleted(event, data) {
        let message = this.getEventCompletedString("Balance", event);
        if (data) {
            message = message.concat(` data = ${dumpValue(data)}`);
        }
        if (!event.exception) { 
            timapi.log(message);
            this.printBalanceResult(data);
            loading.hide();
        }
        super.balanceCompleted(event, data);
    }

    balanceInquiryCompleted(event, data) {
        let message = this.getEventCompletedString(
            "Balance Inquiry Completed",
            event
        );
        if (data) {
            message = message.concat(` data = ${dumpValue(data)}`);
        }
        timapi.log(message);

        super.balanceInquiryCompleted(event, data);
    }

    clientIdentificationCompleted(event, data) {
        let message = this.getEventCompletedString(
            "Client Identification Completed",
            event
        );
        if (data) {
            message = message.concat(` data = ${dumpValue(data)}`);
        }
        timapi.log(message);
        super.clientIdentificationCompleted(event, data);
    }

    changeSettingsCompleted(event) {
        let message = this.getEventCompletedString(
            "Change Settings Completed",
            event
        );
        timapi.log(message);
        super.changeSettingsCompleted(event);
    }


    async transactionCompleted(event, data) {
        let message = this.getEventCompletedString("Transaction", event);
        const $this = this;

        if (event.exception) {
            loading.hide();
            const { resultCode } = event.exception;
            if (resultCode != timapi.constants.ResultCode.apiCancelEcr && resultCode != timapi.constants.ResultCode.cardholderStop) {
                bootbox.confirm({
                    title: 'Transaction Failure',
                    message: event.exception.errorMessage || 'Retry?',
                    buttons: {
                        cancel: {
                            label: 'Cancel'
                        },
                        confirm: {
                            label: 'Retry'
                        }
                    },
                    callback: async function (result) {
                        if (result) {
                            //Retry transaction
                            ecr.actionTransaction(transactionType, trx.Amount, trx.Tips, 0);
                            return;
                        }
                        await $this.saveTrxFailResult(transactionType == 'credit');
                        window.hybridAPP.close(true);
                    },
                    onEscape: false,
                    closeButton: false,
                });
            } else {
                await $this.saveTrxFailResult(transactionType == 'credit');
                window.hybridAPP.close(true);
            }
            timapi.log(message);
            super.transactionCompleted(event, data);
            return;
        }

        if (data) {
            message = message.concat(` data = ${dumpValue(data)}`);
            message = message.concat(`\n`);
            message = message.concat(`\nwasDcc = ${data.wasDcc()}`);
            message = message.concat(`\nwasTip = ${data.wasTip()}`);
            message = message.concat(`\nneedsAction = ${data.needsAction()}`);
            message = message.concat(
                `\nwasPartialApproval = ${data.wasPartialApproval()}`
            );
            message = message.concat(`\ncardCountryCode = ${data.cardCountryCode()}`);
            message = message.concat(
                `\nterminalCountryCode = ${data.terminalCountryCode()}`
            );
            message = message.concat(`\nisDomestic = ${data.isDomestic()}`);
        }
        timapi.log(message);

        // Get transaction information to extract transaction reference numbers.
        // These can be used in a following transaction e.g. in case of reversal.
        if (data != undefined && data.transactionInformation != undefined) {

            switch (data.transactionType) {
                case timapi.constants.TransactionType.purchase:
                case timapi.constants.TransactionType.credit:
                    setTimeout(() => {
                        bootbox.hideAll();
                        lastTransaction = data;
                        timapi.log('Auto Committing...');
                        ecr.actionCommit();
                    }, 1000);
                    break;
                default:
                    break;
            }
        }

        super.transactionCompleted(event, data);
    }

    transactionInfoRequestCompleted(event, data) {
        let message = this.getEventCompletedString("TransactionInfoRequest", event);
        if (data) {
            message = message.concat(` data = ${dumpValue(data)}`);
        }
        timapi.log(message);
        console.info(event, data);

        super.transactionInfoRequestCompleted(event, data);
    }

    async commitCompleted(event, data) {
        let message = this.getEventCompletedString("Commit Completed", event);
        if (data) {
            message = message.concat(` data = ${dumpValue(data)}`);
        }

        timapi.log(message);

        if (!event.exception) {
            await this.saveTrxSuccessResult(lastTransaction, transactionType == timapi.constants.TransactionType.credit);
            window.hybridAPP.close(true);
        }
        loading.hide();
        super.commitCompleted(event, data);
    }

    async rollbackCompleted(event, data) {
        let message = this.getEventCompletedString("Rollback Completed", event);
        if (data) {
            message = message.concat(` data = ${dumpValue(data)}`);
        }

        timapi.log(message);
        if (!event.exception) {
            await this.saveTrxFailResult(transactionType == 'credit');
            window.hybridAPP.close(true);
        }
        loading.hide();
        super.rollbackCompleted(event, data);
    }

    connectCompleted(event) {
        let message = this.getEventCompletedString("Connect Completed", event);
        timapi.log(message);

        if (!event.exception) {
            ecr.connected = true;
            if (ecr.initialConnection) {
                setTimeout(() => ecr.actionInitConnection(), 1000);
            }
        }

        super.connectCompleted(event);
    }

    disconnected(terminal, exception) {
        timapi.log('Disconnected: ', exception);
        ecr.connected = false;
        ecr.loggedIn = false;
        ecr.activated = false;
        ecr.disposeConnection = false;
        setTimeout(() => ecr.disposeTerminal(), 2000);
        console.info(terminal, exception);
    }

    counterRequestCompleted(event, data) {
        let message = this.getEventCompletedString(
            "Counter Request Completed",
            event
        );
        if (data) {
            message = message.concat(` data = ${dumpValue(data)}`);
        }
        timapi.log(message);
        super.counterRequestCompleted(event, data);
    }

    deactivateCompleted(event, data) {
        let message = this.getEventCompletedString("Deactivate Completed", event);
        if (data) {
            message = message.concat(` data = ${dumpValue(data)}`);
        }
        timapi.log(message);

        if (!event.exception) {
            ecr.activated = false;
            if (ecr.disposeConnection) {
                setTimeout(() => ecr.actionDisposeConnection(), 1000);
            }
        }
        super.deactivateCompleted(event, data);
    }

    dccRatesCompleted(event, data) {
        let message = this.getEventCompletedString("DCC Rates Completed", event);
        if (data) {
            message = message.concat(` data = ${dumpValue(data)}`);
        }
        timapi.log(message);
        super.dccRatesCompleted(event, data);
    }

    finishCheckoutCompleted(event, data) {
        let message = this.getEventCompletedString(
            "Finish Checkout Completed",
            event
        );
        if (data) {
            message = message.concat(` data = ${dumpValue(data)}`);
        }
        timapi.log(message);
        super.finishCheckoutCompleted(event, data);
    }

    hardwareInformationCompleted(event, data) {
        let message = this.getEventCompletedString(
            "Hardware Info Completed",
            event
        );
        if (data) {
            message = message.concat(` data = ${dumpValue(data)}`);
        }
        timapi.log(message);
        super.hardwareInformationCompleted(event, data);
    }

    initTransactionCompleted(event, data) {
        let message = this.getEventCompletedString(
            "Init Transaction Completed",
            event
        );
        if (data) {
            message = message.concat(` data = ${dumpValue(data)}`);
        }
        timapi.log(message);
        super.initTransactionCompleted(event, data);
    }

    loginCompleted(event) {
        let message = this.getEventCompletedString("Login Completed", event);
        message = message.concat(` canDcc=${event.terminal.canDcc()}`);
        message = message.concat(
            ` canDeclinedReceipts=${event.terminal.canDeclinedReceipts()}`
        );
        message = message.concat(
            ` canMultiAccountSelection=${event.terminal.canMultiAccountSelection()}`
        );
        message = message.concat(` tid=${event.terminal.getTerminalId()}`);
        message = message.concat(
            `\nfeatures=${dumpValue(event.terminal.getFeatures())}`
        );
        timapi.log(message);

        if (!event.exception) {
            ecr.loggedin = true;
            if (ecr.initialConnection) {
                setTimeout(() => ecr.actionInitConnection(), 1000);
            }
        }

        super.loginCompleted(event);
    }

    logoutCompleted(event) {
        let message = this.getEventCompletedString("Logout Completed", event);
        timapi.log(message);

        if (!event.exception) {
            ecr.loggedin = false;
            if (ecr.disposeConnection) {
                setTimeout(() => ecr.actionDisposeConnection(), 1000);
            }
        }
        super.logoutCompleted(event);
    }

    loyaltyDataCompleted(event, data) {
        let message = this.getEventCompletedString("Loyalty Data Completed", event);
        if (data) {
            message = message.concat(` data = ${dumpValue(data)}`);
        }
        timapi.log(message);

        if (!event.exception) {
            ecr.loggedin = false;
            if (ecr.disposeConnection) {
                setTimeout(() => ecr.actionDisposeConnection(), 1000);
            }
        }

        super.loyaltyDataCompleted(event, data);
    }

    openDialogModeCompleted(event) {
        let message = this.getEventCompletedString(
            "Open Dialog Mode Completed",
            event
        );
        timapi.log(message);
        super.openDialogModeCompleted(event);
    }

    provideLoyaltyBasketCompleted(event, data) {
        let message = this.getEventCompletedString(
            "Provide Loyalty Basket Completed",
            event
        );
        if (data) {
            message = message.concat(` data = ${dumpValue(data)}`);
        }
        timapi.log(message);
        super.provideLoyaltyBasketCompleted(event, data);
    }

    rebootCompleted(event) {
        let message = this.getEventCompletedString("Reboot Completed", event);
        timapi.log(message);
        super.rebootCompleted(event);
    }

    reconciliationCompleted(event, data) {
        let message = this.getEventCompletedString(
            "Reconciliation Completed",
            event
        );
        if (data) {
            message = message.concat(` data = ${dumpValue(data)}`);
        }
        timapi.log(message);
        super.reconciliationCompleted(event, data);
    }

    receiptRequestCompleted(event, data) {
        let message = this.getEventCompletedString(
            "Receipt Request Completed",
            event
        );
        if (data) {
            message = message.concat(` data = ${dumpValue(data)}`);
        }
        timapi.log(message);
        super.receiptRequestCompleted(event, data);
    }

    reconfigCompleted(event, data) {
        let message = this.getEventCompletedString("Reconfig Completed", event);
        if (data) {
            message = message.concat(` data = ${dumpValue(data)}`);
        }
        timapi.log(message);
        super.reconfigCompleted(event, data);
    }

    requestCompleted(event, data) {
        ecr.requestInProgress = undefined;
        let reqName = humanReadableConstName(event.requestType.name);
        let rcName = humanReadableConstName(
            event.exception !== undefined ? event.exception.resultCode.name : "ok"
        );
        timapi.log(`> requestCompleted ${reqName} ${rcName}`);
        if (data) {
            timapi.log(` request data = ${dumpValue(data)}`);
        }
    }

    sendCardCommandCompleted(event, data) {
        let message = this.getEventCompletedString(
            "Send Card Command Completed",
            event
        );
        if (data) {
            message = message.concat(` data = ${dumpValue(data)}`);
        }
        timapi.log(message);
        super.sendCardCommandCompleted(event, data);
    }

    showDialogCompleted(event, data) {
        let message = this.getEventCompletedString("Show Dialog Completed", event);
        if (data) {
            message = message.concat(` data = ${dumpValue(data)}`);
        }
        timapi.log(message);
        super.showDialogCompleted(event, data);
    }

    showSignatureCaptureCompleted(event, data) {
        let message = this.getEventCompletedString(
            "Show Signature Capture Completed",
            event
        );
        if (data) {
            message = message.concat(` data = ${dumpValue(data)}`);
        }
        timapi.log(message);

        // Display signature in the receipt column
        ecr.listenerShowReceipts.printImage(data, "Signature");
        super.showSignatureCaptureCompleted(event, data);
    }

    softwareUpdateCompleted(event, data) {
        let message = this.getEventCompletedString(
            "Software Update Completed",
            event
        );
        if (data) {
            message = message.concat(` data = ${dumpValue(data)}`);
        }
        timapi.log(message);
        super.softwareUpdateCompleted(event, data);
    }

    systemInformationCompleted(event, data) {
        let message = this.getEventCompletedString("System Info Completed", event);
        if (data) {
            message = message.concat(` data = ${dumpValue(data)}`);
            message = message.concat(
                `\n\nconfigData=${dumpValue(event.terminal.getConfigData())}`
            );
        }
        timapi.log(message);
        super.systemInformationCompleted(event, data);
    }


    vasInfo(terminal, vasCheckoutInformation) {
        timapi.log(`VasCheckoutInformation: ${dumpValue(vasCheckoutInformation)}`);
        super.vasInfo(terminal, vasCheckoutInformation);
    }

    screenshot(terminal, screenshotInformation) {
        timapi.log(`ScreenshotInformation: ${dumpValue(screenshotInformation)}`);
        // Display screenshot in the receipt column
        ecr.listenerShowReceipts.printImage(screenshotInformation, "Screenshot");
        super.screenshot(terminal, screenshotInformation);
    }

    /**
     * Create debug-string for event-result; including exception-dump in case of an error
     */
    getEventCompletedString(type, event) {
        let message = `${type} completed: ${humanReadableConstName(
            event.exception !== undefined
                ? event.exception.resultCode.name + "!\n"
                : "ok"
        )}`;
        if (event.exception !== undefined) {
            message = message.concat(`${dumpValue(event.exception)}`);
        }
        return message;
    }

    /*    collectTrxRefNums(data) {
            if (!data) {
                return;
            }
            const ref = {
                trxRefNum: '', trxSeqNum: '', acqTrxRefNum: '', trmTransRef: '', sixTrxRefNum: '', cardRefNum: ''
            }
    
            const tinfo = data.transactionInformation;
            if (tinfo) {
                ref.trxRefNum = tinfo.trmTransRef ?? '';
                ref.trxSeqNum = tinfo.transSeq ?? '';
                ref.acqTrxRefNum = tinfo.acqTransRef ?? '';
                ref.trmTransRef = tinfo.trmTransRef ?? '';
                ref.sixTrxRefNum = tinfo.sixTrxRefNum ?? '';
            }
    
            const cardData = data.cardData;
            if (cardData) {
                ref.cardRefNum = cardData.cardRef ?? '';
            }
    
            return ref;
        }*/


    async saveTrxFailResult(isRefund) {
        const request = {};
        request.BaseAmount = trx.Amount;
        request.TransactionAmount = trx.Amount;
        request.TipAmount = trx.Tips;
        request.SurchargeAmount = 0;
        request.MerchantReceipt = "";
        request.CustomerReceipt = "";
        request.CardType = "";
        request.Result = "FAIL";
        // request.ResultText = JSON.stringify(response);
        request.ResultText = "";
        request.TransactionId = trx.TransactionId;
        request.MachineID = machineID;
        request.EftEnvironment = eftEnvironment;
        request.TransactionReference = "";
        request.IsRefund = +isRefund;
        request.EFTPOSType = 6;
        request.Seq = Seq;

        console.info("trx.completeCallback request.params:", request);
        try {
            await $.ajax({
                type: "POST",
                url: "/api/eft/completeCallback",
                dataType: "json",
                contentType: "application/json;charset=UTF-8",
                headers: {
                    Accept: "application/json; charset=utf-8",
                    ContentType: "application/json; charset=utf-8",
                    MerchantId: merchantId,
                    BranchId: branchId,
                },
                data: JSON.stringify(request),
            });

            console.info("trx.completeCallback response.result:", result);
        } catch (error) {
            console.info("trx.completeCallback response.error:", error);
        }
        setLastSuccessTxn(null);
        lastTransaction = undefined;
        lastSuccessTxn = null;
    }

    async saveTrxSuccessResult(response, isRefund) {
        const request = {};
        let merchantReceipt = "";
        let customerReceipt = "";
        let cardType = "";
        request.BaseAmount = response.amount.getDecimalValue();
        request.TransactionAmount = response.amount.getDecimalValue();
        request.TipAmount =
            response.amountTip !== undefined
                ? response.amountTip.getDecimalValue()
                : 0;
        request.SurchargeAmount =
            response.amountSurcharge !== undefined
                ? response.amountSurcharge.getDecimalValue()
                : 0;

        if (response.printData !== undefined) {
            const { printData } = response;
            if (printData.receipts !== undefined) {
                const { receipts } = printData;
                for (var i = 0; i < receipts.length; i++) {
                    if (receipts[i].recipient == timapi.constants.Recipient.merchant) {
                        merchantReceipt = receipts[i].value;
                    }
                    if (receipts[i].recipient == timapi.constants.Recipient.cardholder) {
                        customerReceipt = receipts[i].value;
                    }
                }
            }
        }
        request.MerchantReceipt = merchantReceipt;
        request.CustomerReceipt = customerReceipt;

        if (response.cardData !== undefined) {
            const { cardData } = response;
            cardType = cardData.brandName;
        }
        request.CardType = cardType;
        request.Result = "APPROVED";
        // request.ResultText = JSON.stringify(response);
        request.ResultText = "";
        request.TransactionId = trx.TransactionId;
        request.MachineID = machineID;
        request.EftEnvironment = eftEnvironment;
        request.TransactionReference = response.transactionInformation.transRef;
        request.IsRefund = +isRefund;
        request.EFTPOSType = 6;
        request.Seq = Seq;

        console.info("trx.completeCallback request.params:", request);
        try {
            await $.ajax({
                type: "POST",
                url: "/api/eft/completeCallback",
                dataType: "json",
                contentType: "application/json;charset=UTF-8",
                headers: {
                    Accept: "application/json; charset=utf-8",
                    ContentType: "application/json; charset=utf-8",
                    MerchantId: merchantId,
                    BranchId: branchId,
                },
                data: JSON.stringify(request),
            });

            console.info("trx.completeCallback response.result:", result);
        } catch (error) {
            console.info("trx.completeCallback response.error:", error);
        }

        setLastSuccessTxn(lastTransaction);
        lastTransaction = undefined;
        lastSuccessTxn = null;
    }

    async printBalanceResult(response) {
        let merchantReceipt = "";
        if (response.printData !== undefined) {
            const { printData } = response;
            if (printData.receipts !== undefined) {
                const { receipts } = printData;
                for (var i = 0; i < receipts.length; i++) {
                    if (receipts[i].recipient == timapi.constants.Recipient.merchant) {
                        merchantReceipt = receipts[i].value;
                    }
                }
            }
        }
        const req = {};
        req.MachineID = machineID;
        req.MerchantReceipt = merchantReceipt;
        req.Seq = Seq;
        console.info("maint.balancePrintCallback request.params:", req);
        try {
            await $.ajax({
                type: "POST",
                headers: {
                    Accept: "application/json; charset=utf-8",
                    ContentType: "application/json; charset=utf-8",
                    MerchantId: merchantId,
                    BranchId: branchId
                },
                url: "/api/eft/settlementPrintCallback",
                data: JSON.stringify(req),
                dataType: "json",
                contentType: "application/json;charset=UTF-8",
            });
            console.info("maint.balancePrintCallback response.result", result);
        } catch (error) {
            console.info("maint.balancePrintCallback response.error:", error.responseText);
        }

    }

}
