import { initializeInputToggle } from '../utils/show-hide-input';
import { updateOrderSummary } from './order-summary';
import { hideLoader, showLoader, appendLoader } from '../utils/loader';
import {
    ADD_GIFT_CARD,
    buildHintContext,
    buildSummaryEqualMap,
    formatGc16,
    isZeroAmount,
    linkifyClickHere,
    MESSAGE_BY_CODE,
    OK_CODE,
    PAY_WITH_GIFT_CARD,
    payWithGiftCard,
    REMOVE_GIFT_CARD,
    removeGiftCard,
    verifyGiftCard,
    PAY_MESSAGE_BY_CODE,
    DEFAULT_ERROR_MESSAGE,
    DEFAULT_PAY_ERROR_MESSAGE,
} from '../utils/gift-cards-utils';

import { clearErrorText, validateExactDigits } from '../utils/validation';
import {
    createGcNumberInputHandler,
    digitsOnlyKeypress,
    handleGcNumberBlur,
    handleGcPinInput,
    handleGcPinKeypress,
    handleGcPinBlur,
} from '../utils/input-handling';

const Handlebars = require('hbsfy/runtime');

Handlebars.registerPartial('info-icon', require('../../../components/info-icon.hbs'));
Handlebars.registerPartial('loader', require('../../../elements/loader.hbs'));

const giftCardsHint = require('../../../components/gift-cards-hint.hbs');
const giftCardChip = require('../../../components/giftcard-chip.hbs');
const giftcardSummary = require('../../../components/giftcard-summary.hbs');
const notificationTpl = require('../../../elements/notifications.hbs');

var Wick = window.Wick || {};

Wick.GiftCard = {
    ADD_GIFT_CARD,
    REMOVE_GIFT_CARD,
    PAY_WITH_GIFT_CARD,
    el: {
        $blocks: $('.giftcard'),
        block: '.giftcard',
        toggle: '#giftcard-toggle',
        panel: '#giftcard-inline',
        hint: '.giftcard-hint',
        closeBtn: '.giftcard-inline__close',
        form: '.giftcard-inline__form',
        number: 'input[name="giftcard-number"]',
        pin: 'input[name="giftcard-pin"]',
        note: '.giftcard-note',
        field: '.giftcard__field',
        errorText: '.giftcard__error-text',
        fieldError: 'giftcard-field--error',
        showToggle: '.toggle-show',
        loader: '.giftcard__container .loader-wrapper',
        success: '#giftcard-applied',
        container: '.giftcard__container',
        paymentForm: '.checkout-payment-details__payment-method',
        billieField: '.form-row__field.form-row__field-billie',
        klarnaField: '.form-row__field.form-row__field-klarna',
        clearpayField: '.form-row__field.form-row__field-clearpay',
        appleField: '.form-row__field.form-row__field-apple',
        googleField: '.form-row__field.form-row__field-google',
        paypalField: '.form-row__field.form-row__field-paypal',
        cardField: '.form-row__field.form-row__card-payment',
        summaryHint: '.giftcard-summary__hint',
        chipList: '.giftcard-chip-list',
        summary: '.giftcard-summary',
        chip: '.giftcard-chip',
        giftcardRow: '.giftcard-row',
        checkoutContainer: '.checkout-payment-details',
        formRow: '.form-row',
        iconInfo: '.icon-info-component',
        toggleIcon: 'svg, i',
        iconEye: 'fa-eye',
        iconEyeSlash: 'fa-eye-slash',
        iconSvgEyeSlash: 'eye-slash',
        passwordToggleEvent: 'input.passwordToggle',
        ariaInvalidAttr: 'aria-invalid',
        typeAttr: 'type',
        dataIconAttr: 'data-icon',
        svg: 'svg',
        expandedAttr: 'aria-expanded',
        giftcardBtn: '.giftcard__btn',
        jsGiftcardAdd: '.js-giftcard-add',
        giftcardChipClose: '.giftcard-chip__close',
        body: 'body',
        loaderChip: '.loader-wrapper',
        chipListLoader: '.giftcard-chip-list > .loader-wrapper',
        notification: '.giftcard-inline .notification',
        giftCardInline: '.giftcard-inline',
        notificationRoot: '.notification',
        inlineHeader: '.giftcard-inline__header',
        ctaSelector: '.btn-enter-details',
        btnDetails: 'button',
        btnText: '.btn__text',
        btnEnterDetails: '.btn-enter-details',
        checkoutPaymentFields: '.billing-address .checkout-payment-details__descr',
        pageLoader: '.loader-wrapper.page-loader',
        cardRadio: '#checkout-payment-details-card, #_checkout-payment-details-card_card',
        billieInfo: '.checkout-payment-details__billie',
        klarnaInfo: '.checkout-payment-details__klarna',
        billingAddress: '.billing-address',
        altPaymentRowsAttr:
            '[data-apple-pay],[data-google-pay],[data-paypal],[data-klarna],[data-billie],[data-clearpay],[data-existing-card]',
        hiddenCard: 'checkout-payment-details__card-details_hidden',
        cardDetails: '.checkout-payment-details__card-details',
    },

    messages: {
        numberMessage: 'Gift Card should consist of 16 digits',
        pinMessage: 'Gift Card PIN should consist of 8 digits',
        ctaDefaultText: 'Enter card details',
        ctaGiftcardText: 'Pay with Gift Card',
    },

    maxChips: 3,
    successTimer: null,
    pendingServerGiftCards: null,
    altPaymentInfosLocked: false,
    altPaymentPanelsLocked: false,
    summaryTotal: null,

    resetPinToggle($root) {
        const {
            pin,
            field,
            showToggle,
            toggleIcon,
            iconEye,
            iconEyeSlash,
            iconSvgEyeSlash,
            passwordToggleEvent,
            typeAttr,
            dataIconAttr,
            svg,
        } = this.el;

        const $pinField = $root.find(pin).closest(field);
        const $pinInput = $pinField.find(pin).first();

        $pinInput.attr(typeAttr, 'password');

        const $toggle = $pinField.find(showToggle).first();
        const $icon = $toggle.find(toggleIcon).first();

        if ($icon.length) {
            $icon.removeClass(`${iconEye} ${iconEyeSlash}`).addClass(iconEyeSlash);
            if ($icon.is(svg) && $icon.attr(dataIconAttr)) {
                $icon.attr(dataIconAttr, iconSvgEyeSlash);
            }
        }

        const hasValue = ($pinInput.val() || '').length > 0;
        $toggle.toggle(hasValue);

        $pinInput.trigger(passwordToggleEvent);
    },

    resetForm($root) {
        const { number, pin, note } = this.el;
        const $num = $root.find(number);
        const $pinInput = $root.find(pin);

        $num.val('');
        $pinInput.val('');
        clearErrorText(
            $num,
            this.el.field,
            this.el.errorText,
            this.el.fieldError,
            this.el.ariaInvalidAttr
        );
        clearErrorText(
            $pinInput,
            this.el.field,
            this.el.errorText,
            this.el.fieldError,
            this.el.ariaInvalidAttr
        );
        $root.find(note).remove();

        this.hideBanner($root);
        this.resetPinToggle($root);
    },

    open($root) {
        const { toggle, panel, hint, pin, expandedAttr, passwordToggleEvent } = this.el;
        this.hideBanner($root);
        $root.show();

        $root.find(panel).prop('hidden', false);
        $root.find(toggle).attr(expandedAttr, 'true').hide();
        $root.find(hint).hide();
        $root.find(pin).trigger(passwordToggleEvent);
    },

    close($root) {
        const { toggle, panel, loader, expandedAttr } = this.el;
        const $toggle = $root.find(toggle);
        const $panel = $root.find(panel);
        const $loader = $root.find(loader);

        showLoader($loader);

        setTimeout(() => {
            hideLoader($loader);

            $panel.prop('hidden', true);
            $toggle.attr(expandedAttr, 'false').show().trigger('focus');
            this.updateHintVisibility($root);
        }, 1000);
    },

    showSubmitSpinner($root) {
        const { panel, toggle, hint, expandedAttr } = this.el;
        $root.find(panel).prop('hidden', true);
        $root.find(toggle).attr(expandedAttr, 'false').show().trigger('focus');
        $root.find(hint).show();
        this.showSuccess($root);
    },

    handleToggleClick(e) {
        e.preventDefault();
        this.open($(e.currentTarget).closest(this.el.$blocks));
    },

    handleCloseClick(e) {
        e.preventDefault();
        const $root = $(e.currentTarget).closest(this.el.$blocks);
        this.resetForm($root);
        this.close($root);
    },

    finalizeSuccess($root, $success) {
        let { panel, toggle, hint, expandedAttr } = this.el;

        if ($success && $success.length) {
            $success.attr('hidden', 'hidden').removeClass('fade show').off('transitionend');
        }

        this.resetForm($root);
        $root.find(panel).prop('hidden', true);
        $root.find(toggle).attr(expandedAttr, 'false').show();
        $root.find(hint).show();

        if (this.pendingServerGiftCards) {
            this.renderGiftCardsFromList($root, this.pendingServerGiftCards);
            this.pendingServerGiftCards = null;
        }

        this.updateHintVisibility($root);
        this.successTimer = null;
    },

    showSuccess($root) {
        const { success } = this.el;

        if (this.successTimer) {
            clearTimeout(this.successTimer);
            this.successTimer = null;
        }

        $root.hide();
        const $success = $(success);
        $success.removeAttr('hidden').addClass('fade');
        $success[0] && $success[0].offsetWidth;
        $success.addClass('show');

        this.successTimer = setTimeout(() => {
            $success.removeClass('show');
            const handler = () => this.finalizeSuccess($root, $success);

            $success.on('transitionend', handler);
            setTimeout(handler, 200);
        }, 3000);
    },

    handleFormSubmit(e) {
        const { number, block, giftcardRow, loaderChip } = this.el;
        e.preventDefault();

        const $root = $(e.currentTarget).closest(block);
        this.hideBanner($root);

        const $num = $root.find(number);
        $num.val(formatGc16($num.val()));

        const $numInput = $root.find(this.el.number);
        const $pinInput = $root.find(this.el.pin);

        const numberBlurOpts = {
            fieldSelector: this.el.field,
            errorTextSelector: this.el.errorText,
            errorClass: this.el.fieldError,
            ariaInvalidAttr: this.el.ariaInvalidAttr,
            numberMessage: this.messages.numberMessage,
        };

        const pinBlurOpts = {
            fieldSelector: this.el.field,
            errorTextSelector: this.el.errorText,
            errorClass: this.el.fieldError,
            ariaInvalidAttr: this.el.ariaInvalidAttr,
            pinMessage: this.messages.pinMessage,
        };

        const okNumber = validateExactDigits($numInput, 16, this.messages.numberMessage, this.el);
        const okPin = validateExactDigits($pinInput, 8, this.messages.pinMessage, this.el);

        if (!(okNumber && okPin)) {
            handleGcNumberBlur({ currentTarget: $numInput[0] }, numberBlurOpts);
            handleGcPinBlur({ currentTarget: $pinInput[0] }, pinBlurOpts);
            (!okNumber ? $numInput : $pinInput).trigger('focus');
            return;
        }

        const giftCardNumber = this.getNumberValue($root);
        const pin = this.getPinValue($root);
        const $row = $root.closest(giftcardRow);

        let $loader = $row.children(loaderChip);

        if (!$loader.length) {
            appendLoader({ wrapper: $row });
            $loader = $row.children(loaderChip).last();
        }

        verifyGiftCard($loader, giftCardNumber, pin)
            .then((res) => this.handleVerifyResponse($root, res))
            .catch((err) => {
                const msg = this.getErrorMessage(err);
                this.showBannerError($root, msg);
            });
    },

    handleVerifyResponse($root, res) {
        if (res && res.code === OK_CODE) {
            if (!Array.isArray(res.giftCards)) {
                this.showBannerError($root, DEFAULT_ERROR_MESSAGE);
                return;
            }

            this.pendingServerGiftCards = res.giftCards.slice();

            if (res.orderTotal != null || res.giftCardTotal != null) {
                const data = { total: res.orderTotal, giftCardApplied: res.giftCardTotal };
                updateOrderSummary(data, buildSummaryEqualMap(data), true);
                this.summaryTotal = res.orderTotal;
                this.toggleBillingDescrForZero($root);
                this.updateCtaButton($root);
            }

            this.resetForm($root);
            this.showSubmitSpinner($root);
            return;
        }

        const msg = (res && MESSAGE_BY_CODE[res.code]) || DEFAULT_ERROR_MESSAGE;
        this.showBannerError($root, msg);
    },

    updateHintVisibility($root) {
        const {
            chipList,
            giftcardRow,
            hint,
            panel,
            toggle,
            iconInfo,
            expandedAttr,
            summaryHint,
            chip,
            block,
            body,
        } = this.el;

        const $row = $root.closest(giftcardRow);
        const $giftcard = $row.find(block).first();
        const count = $row.find(`${chipList} ${chip}`).length;
        const limit = this.maxChips || 3;

        const zeroTotal = this.summaryTotal != null ? isZeroAmount(this.summaryTotal) : false;

        this.toggleAltPayments($giftcard, count === 0);
        this.toggleAltPaymentInfos($giftcard, count === 0);

        if (count > 0) {
            if (!this.altPaymentPanelsLocked) {
                this.showOnlyBillingAddress($giftcard);
                this.altPaymentPanelsLocked = true;
            } else {
                this.showOnlyBillingAddress($giftcard);
            }
        } else {
            if (!this.altPaymentPanelsLocked) {
                this.toggleAltPayments($giftcard, true);
                this.toggleAltPaymentInfos($giftcard, true);
            } else {
                this.showOnlyBillingAddress($giftcard);
            }
        }

        const $summary = this.ensureSummaryContainer($giftcard);

        if (count === 0) {
            $summary.hide();
            $giftcard.show();
            this.resetForm($giftcard);
            $giftcard.find(panel).prop('hidden', true);
            $giftcard.find(toggle).attr(expandedAttr, 'false').show();
            $giftcard.find(hint)[zeroTotal ? 'hide' : 'show']();
            this.updateCtaButton($giftcard);
            return;
        }

        this.setBillingLabelToCard($giftcard);
        $summary.show();
        $giftcard.hide();
        $giftcard.find(hint).hide();

        const ctx = buildHintContext(count, limit, zeroTotal);
        const html = giftCardsHint(ctx);
        const $old = $summary.find(summaryHint).first();
        const $new = $(html);

        if ($old.length) $old.replaceWith($new);
        else $summary.append($new);

        if (zeroTotal) {
            $summary.find(summaryHint).hide();
        }

        this.toggleCardDetailsForTotal($giftcard);

        if ($.fn.tooltip) {
            $summary.find(summaryHint).find(iconInfo).tooltip({ container: body });
        }
    },

    renderChipHTML({ id, maskedNumber, currency, amount }) {
        return giftCardChip({ id, maskedNumber, currency, amount });
    },

    toggleAltPaymentInfos($root, show) {
        const { checkoutContainer, billieInfo, klarnaInfo } = this.el;
        const $container = $root.closest(checkoutContainer);

        if (this.altPaymentInfosLocked) {
            show = false;
        }

        [$container.find(billieInfo), $container.find(klarnaInfo)].forEach(($panel) => {
            if ($panel && $panel.length) {
                $panel[show ? 'show' : 'hide']();
            }
        });

        if (!show) this.altPaymentInfosLocked = true;
    },

    toggleAltPayments($root, show) {
        const {
            paymentForm,
            billieField,
            klarnaField,
            clearpayField,
            appleField,
            googleField,
            paypalField,
            checkoutContainer,
            formRow,
            cardField,
        } = this.el;

        const $container = $root.closest(checkoutContainer);
        const $paymentField = $container.find(paymentForm);
        const isTotalZero = this.summaryTotal != null ? isZeroAmount(this.summaryTotal) : false;

        const paymentSelectors = [
            billieField,
            klarnaField,
            clearpayField,
            appleField,
            googleField,
            paypalField,
        ];

        paymentSelectors.forEach((sel) => {
            const $row = $paymentField.find(sel).closest(formRow);
            if ($row.length) {
                const shouldShow = show && !isTotalZero;
                $row[shouldShow ? 'show' : 'hide']();
            }
        });

        const $cardRow = $paymentField.find(cardField).closest(formRow);
        if ($cardRow.length) {
            $cardRow[isTotalZero ? 'hide' : 'show']();
        }

        if (!show) {
            this.ensureCardPaymentSelected($paymentField);
        }
    },

    ensureCardPaymentSelected($paymentField) {
        const { cardField, cardRadio, formRow } = this.el;

        const $cardFieldRow = $paymentField.find(cardField).closest(formRow);
        if (!$cardFieldRow.length) {
            return;
        }

        const $radio = $cardFieldRow.find(cardRadio);

        if ($radio.length && !$radio.prop('checked')) {
            $radio.prop('checked', true);
            $radio.trigger('change');
            this.updateCtaButton($cardFieldRow);
        }
    },

    handleAddAnotherClick(e) {
        e.preventDefault();
        const { giftcardRow, chipList, chip, block, number, summaryHint } = this.el;

        const $row = $(e.currentTarget).closest(giftcardRow);
        const count = $row.find(`${chipList} ${chip}`).length;
        if (count >= this.maxChips) return;

        const $giftcard = $row.find(block).first();
        this.resetForm($giftcard);
        this.open($giftcard);

        $row.find(summaryHint).hide();

        setTimeout(() => {
            $giftcard.find(number).trigger('focus');
        }, 0);
    },

    getErrorMessage(payload) {
        const code =
            payload && (typeof payload.code === 'number' || typeof payload.code === 'string')
                ? payload.code
                : undefined;

        return (code != null && MESSAGE_BY_CODE[code]) || DEFAULT_ERROR_MESSAGE;
    },

    handleChipCloseClick(e) {
        e.preventDefault();
        const { chip, giftcardRow, block, giftcardChipClose, chipList, loaderChip } = this.el;

        const $clickedChip = $(e.currentTarget).closest(chip);
        const $row = $clickedChip.closest(giftcardRow);
        const $giftcard = $row.find(block).first();
        const $summary = this.ensureSummaryContainer($giftcard);

        const $chips = $summary.find(`${chipList} ${chip}`);
        const index = $chips.index($clickedChip);
        if (index < 0) return;

        let $loader = $row.children(loaderChip);
        if (!$loader.length) {
            appendLoader({ wrapper: $row });
            $loader = $row.children(loaderChip).last();
        }

        $row.find(giftcardChipClose).css('pointer-events', 'none').attr('aria-disabled', 'true');

        removeGiftCard($loader, index)
            .then((res) => this.handleRemoveResponse($giftcard, res))
            .catch((err) => {
                const msg = this.getErrorMessage(err);
                this.showBannerError($giftcard, msg);
            })
            .finally(() => {
                hideLoader($loader);
                $row.find(giftcardChipClose).css('pointer-events', '').removeAttr('aria-disabled');
            });
    },

    handleRemoveResponse($giftcard, res) {
        if (res && res.code === OK_CODE) {
            const giftCardsList = Array.isArray(res.giftCards) ? res.giftCards : [];
            const data = { total: res.orderTotal, giftCardApplied: res.giftCardTotal };
            this.summaryTotal = res.orderTotal;

            this.renderGiftCardsFromList($giftcard, giftCardsList, data);

            if (res.orderTotal != null || res.giftCardTotal != null) {
                updateOrderSummary(data, buildSummaryEqualMap(data), true);
            }
            this.updateCtaButton($giftcard);
            this.toggleBillingDescrForZero($giftcard);
            return;
        }

        const msg = (res && MESSAGE_BY_CODE[res.code]) || DEFAULT_ERROR_MESSAGE;
        this.showBannerError($giftcard, msg);
    },

    ensureSummaryContainer($root) {
        const { summary, giftcardRow } = this.el;
        const $row = $root.closest(giftcardRow);
        let $summary = $row.find(summary).first();

        if (!$summary.length) {
            $summary = $(giftcardSummary({}));
            $row.append($summary);
        }

        return $summary;
    },

    getPageLoader() {
        const $pl = $(this.el.pageLoader);
        if (!$pl.parent().is('body')) $pl.appendTo('body');
        return $pl;
    },

    showPageLoader() {
        const $pl = this.getPageLoader();
        showLoader($pl);
    },

    updateCtaButton($scope) {
        const { ctaSelector, btnDetails, btnText, checkoutContainer } = this.el;
        let $cta = $(ctaSelector);
        if (!$cta.length) {
            $cta = $scope.closest(checkoutContainer).find(ctaSelector);
        }
        if (!$cta.length) return;

        const $wrap = $cta.closest(btnDetails).length ? $cta.closest(btnDetails) : $cta;
        const $text = $wrap.find(btnText).first().length ? $wrap.find(btnText).first() : $wrap;
        const useGiftcard = isZeroAmount(this.summaryTotal);

        $text.text(useGiftcard ? this.messages.ctaGiftcardText : this.messages.ctaDefaultText);
        $wrap.attr('data-mode', useGiftcard ? 'giftcards' : 'card');

        if (useGiftcard) {
            $wrap.attr('type', 'button').removeAttr('form');
        } else {
            $wrap.attr('type', 'submit').attr('form', 'hopPaymentAddressPostForm');
        }
    },

    toggleBillingDescrForZero($scope) {
        const $container = $scope.closest(this.el.checkoutContainer);
        const $descr = $container.find(this.el.checkoutPaymentFields);
        if (!$descr.length) return;

        const shouldHide = isZeroAmount(this.summaryTotal);
        $descr[shouldHide ? 'hide' : 'show']();
    },

    getNumberValue($root) {
        const { number } = this.el;
        return String($root.find(number).val() || '').replace(/\D/g, '');
    },

    getPinValue($root) {
        const { pin } = this.el;
        return String($root.find(pin).val() || '').replace(/\D/g, '');
    },

    bindGiftcardCtaHandler() {
        const self = this;

        $(document).off('click.giftcard', this.el.btnEnterDetails);
        $(document).on('click.giftcard', this.el.btnEnterDetails, function (e) {
            const $btn = $(this);
            const mode = $btn.attr('data-mode');

            if (mode !== 'giftcards') return;

            e.preventDefault();
            e.stopPropagation();
            e.stopImmediatePropagation();

            const $scope = $btn.closest(self.el.checkoutContainer).find(self.el.block).first();
            const $root = $scope.length ? $scope : $(self.el.block).first();

            self.showPageLoader();

            payWithGiftCard()
                .then(({ url }) => {
                    if (typeof url === 'string' && url) {
                        window.location.href = url;
                    }
                })
                .catch((error) => {
                    if (Array.isArray(error?.giftCards)) {
                        self.renderGiftCardsFromList($root, error.giftCards);
                    }

                    const msg =
                        (error.errorCode && PAY_MESSAGE_BY_CODE[error.errorCode]) ||
                        DEFAULT_PAY_ERROR_MESSAGE;

                    if (msg) {
                        Wick.Notification.show({
                            text: linkifyClickHere(msg),
                            container: '.globalMessages .container',
                            type: 'error',
                        });
                    }
                })
                .finally(() => {
                    const $pl = self.getPageLoader();
                    hideLoader($pl);
                });
        });
    },

    showBannerError($root, message, title = '') {
        const { notificationRoot, giftCardInline, inlineHeader } = this.el;
        const $inline = $root.find(giftCardInline);

        $inline.find(notificationRoot).remove();

        const html = notificationTpl({
            classModifier: 'notification_error',
            error: true,
            withCloseBtn: true,
            title: title || undefined,
            text: linkifyClickHere(message),
        });

        $inline.find(inlineHeader).after(html);
    },

    hideBanner($root) {
        const { notification } = this.el;
        $root.find(notification).remove();
    },

    mapGiftToChipData($root, gift) {
        const $giftcard = $root.closest(this.el.block);
        const currency = $giftcard.data('currency') || '£';
        const rawAmount = Number(gift.amountToRedeem || 0);
        const amount = Number.isFinite(rawAmount) ? rawAmount.toFixed(2) : '0.00';
        return {
            id: gift.id,
            maskedNumber: String(gift.maskedNumber || ''),
            currency,
            amount,
        };
    },

    renderGiftCardsFromList($root, giftCards, summaryData) {
        const { chipList, loaderChip, chip } = this.el;
        const $summary = this.ensureSummaryContainer($root);
        const $list = $summary.find(chipList);
        $list.children(`${chip}:not(${loaderChip})`).remove();

        const html = (giftCards || [])
            .map((g) => this.renderChipHTML(this.mapGiftToChipData($root, g)))
            .join('');

        if (html) {
            $list.append(html);
            $summary.show();
        }

        this.updateHintVisibility($root, summaryData);

        if (Array.isArray(giftCards) && giftCards.length > 0) {
            this.setBillingLabelToCard($root);
        }
    },

    toggleCardDetailsForTotal($scope) {
        const { checkoutContainer, cardDetails, hiddenCard } = this.el;
        const $container = $scope.closest(checkoutContainer);
        const $cardDetails = $container.find(cardDetails);
        if (!$cardDetails.length) return;

        const zero = this.summaryTotal != null ? isZeroAmount(this.summaryTotal) : false;
        if (zero) $cardDetails.addClass(hiddenCard);
    },

    setBillingLabelToCard($scope) {
        const $container = $scope.closest(this.el.checkoutContainer);
        const $billing = $container.find(this.el.billingAddress);
        if (!$billing.length) return;

        const $label = $billing.find('[for="card-name"]');
        if ($label.length) {
            $label.text('Name on card');
        }
    },

    showOnlyBillingAddress($root) {
        const { checkoutContainer, billingAddress, altPaymentRowsAttr, hiddenCard } = this.el;
        const $container = $root.closest(checkoutContainer);
        $container.find(billingAddress).removeClass(hiddenCard);
        $container.find(altPaymentRowsAttr).addClass(hiddenCard);
        this.toggleAltPaymentInfos($root, false);
    },

    useGlobalError($root, message) {
        if (window.Wick && Wick.Notification && typeof Wick.Notification.show === 'function') {
            const text = linkifyClickHere ? linkifyClickHere(message) : String(message || '');
            const containers = ['.globalMessages .container', '.globalMessages.container'];
            const container = containers.find((selector) => $(selector).length);

            if (!container) {
                return;
            }

            Wick.Notification.show({
                text,
                container,
                type: 'error',
            });
        }
    },

    bindSplitPaymentFailedListener() {
        window.addEventListener('cardSplitPaymentFailed', (event) => {
            const code = event?.detail?.externalErrorCode;
            if (!code) {
                return;
            }

            const msg = PAY_MESSAGE_BY_CODE[code] || DEFAULT_PAY_ERROR_MESSAGE;
            this.useGlobalError(this.el.$blocks.first(), msg);
        });
    },

    bindEvents() {
        const { number, pin, toggle, closeBtn, giftcardBtn, jsGiftcardAdd, giftcardChipClose } =
            this.el;

        $(document).off('.giftcard');

        const handleNumberInput = createGcNumberInputHandler({
            fieldSelector: this.el.field,
            fieldErrorClass: this.el.fieldError,
            errorTextSelector: this.el.errorText,
            ariaInvalidAttr: this.el.ariaInvalidAttr,
        });

        const onNumberBlur = (e) =>
            handleGcNumberBlur(e, {
                fieldSelector: this.el.field,
                errorTextSelector: this.el.errorText,
                errorClass: this.el.fieldError,
                ariaInvalidAttr: this.el.ariaInvalidAttr,
                numberMessage: this.messages.numberMessage,
            });

        const onPinInput = (e) =>
            handleGcPinInput(e, {
                fieldSelector: this.el.field,
                errorTextSelector: this.el.errorText,
                errorClass: this.el.fieldError,
                ariaInvalidAttr: this.el.ariaInvalidAttr,
            });

        const onPinBlur = (e) =>
            handleGcPinBlur(e, {
                fieldSelector: this.el.field,
                errorTextSelector: this.el.errorText,
                errorClass: this.el.fieldError,
                ariaInvalidAttr: this.el.ariaInvalidAttr,
                pinMessage: this.messages.pinMessage,
            });

        $(document)
            .on('input.giftcard', number, handleNumberInput)
            .on('keypress.giftcard', number, digitsOnlyKeypress)
            .on('blur.giftcard', number, onNumberBlur);

        $(document)
            .on('input.giftcard', pin, onPinInput)
            .on('keypress.giftcard', pin, handleGcPinKeypress)
            .on('blur.giftcard', pin, onPinBlur);

        $(document)
            .on('click.giftcard', toggle, this.handleToggleClick.bind(this))
            .on('click.giftcard', closeBtn, this.handleCloseClick.bind(this))
            .on('click.giftcard', giftcardBtn, this.handleFormSubmit.bind(this))
            .on('click.giftcard', jsGiftcardAdd, this.handleAddAnotherClick.bind(this))
            .on('click.giftcard', giftcardChipClose, this.handleChipCloseClick.bind(this));

        this.bindGiftcardCtaHandler();
    },

    init(payload = {}) {
        const { field, pin, $blocks } = this.el;
        this.bindEvents();
        this.bindSplitPaymentFailedListener();
        if ($blocks && $blocks.length) {
            const $firstBlock = $blocks.first();
            if (Array.isArray(payload.giftCards) && payload.giftCards.length) {
                this.renderGiftCardsFromList($firstBlock, payload.giftCards);
            }

            const code = payload.errorCode;

            if (Number.isFinite(code) && PAY_MESSAGE_BY_CODE[code]) {
                this.useGlobalError($firstBlock, PAY_MESSAGE_BY_CODE[code]);
            }
        }

        $blocks.each((index, block) => {
            const $pinField = $(block).find(pin).closest(field);
            if ($pinField.length) {
                initializeInputToggle($pinField);
            }
        });
    },
};
