var Wick = window.Wick || {};

import { createCountStepper } from './utils/create-count-stepper';
import { createEvent } from './utils/create-event';
import { createDropdown } from './utils/custom-dropdown';
import { createLoadingButton } from './utils/create-loading-button';
import { createToast } from './utils/create-toast';

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

Handlebars.registerPartial('checkbox', require('../../elements/checkbox.hbs'));
Handlebars.registerPartial('loader', require('../../elements/loader.hbs'));
Handlebars.registerPartial('button', require('../../components/base/button.hbs'));
Handlebars.registerPartial(
    'bloomreach/complete-card-dropdown',
    require('../../components/bloomreach/complete-card-dropdown.hbs')
);
Handlebars.registerPartial('notifications', require('../../elements/notifications.hbs'));

const notificationTemplate = require('../../elements/notifications.hbs');
const completeWrapperTemplate = require('../../components/bloomreach/complete-wrapper.hbs');
const completeDividerTemplate = require('../../components/bloomreach/complete-divider.hbs');
const completeCardTemplate = require('../../components/bloomreach/complete-card.hbs');
const completeSummaryTemplate = require('../../components/bloomreach/complete-summary.hbs');

Wick.BloomreachWidget = {
    CALCULATE_PRODUCT_BUNDLE_TOTAL_EVENT: 'calculateProductBundleTotal',
    ADD_PRODUCT_BUNDLE_TO_CART_EVENT: 'bulkAddToCart',

    steppers: [],
    recommendations: [],
    dropdown: null,
    loadingButton: null,
    lastCalculationResponse: null,
    dropdownCurrent: {},
    toast: null,

    el: {
        cardCheckbox: '.complete-card__select input[type="checkbox"]',
        completeCard: '.complete-card',
        completeWidget: '.complete-widget',
        countBtn: '.count-btn',
        countStepperInitializedData: 'count-stepper-initialized',
        countStepperRoot: '.count-stepper',
        ctaButton: '.complete-widget__cta .btn',
        ctaButtonText: '.loading-button__text',
        ctaButtonLoader: '.loading-button__loader',
        summaryPriceValue: '.complete-widget__price-value',
        summarySalePrice: '.complete-widget__sale-price',
        summaryPriceInc: '.including-vat-inherit',
        summaryPriceExc: '.excluding-vat-inherit',
        summarySalePriceInc: '.including-vat-inherit',
        summarySalePriceExc: '.excluding-vat-inherit',

        dropdownErrorClass: 'complete-card-dropdown--error',
        dropdownOpenClass: 'complete-card-dropdown--open',
        dropdownOption: '[data-complete-card-dropdown-option]',
        dropdownOptionSelectedClass: 'complete-card-dropdown__option--selected',
        dropdownRoot: '[data-complete-card-dropdown]',
        dropdownToggle: '[data-complete-card-dropdown-toggle]',
        dropdownValue: '[data-complete-card-dropdown-value]',

        optionsEl: '.complete-card__options',
        previousQuantityData: 'previous-quantity',
        quantityInput: '.tbx_quantity',
        quantityReadyData: 'quantity-ready',

        recommendationIndexAttr: 'data-recommendation-index',
        selectedClass: 'complete-card--selected',
        selectedValueData: 'selected-value',
        starOverlay: '.star-overlay',

        titleEl: '.complete-card__title',

        widgetContainer: '[data-complete-widget]',
        widgetContent: '[data-complete-widget-content]',
        widgetWrapper: '[data-complete-widget-wrapper]',
    },

    badgeColorMap: {
        blue: '#019ee3',
        gray: '#3e3e3e',
        green: '#9acd32',
        red: '#cf000f',
        yellow: '#f7ca18',
    },

    getCtaText(selectedCount) {
        if (!selectedCount) {
            return 'Add product(s) to basket';
        }

        return `Add ${selectedCount} product${selectedCount > 1 ? 's' : ''} to basket`;
    },

    setCtaText($button, text) {
        const { ctaButtonText } = Wick.BloomreachWidget.el;
        const $text = $button.find(ctaButtonText);

        if ($text.length) {
            $text.text(text);
            return;
        }

        $button.text(text);
    },

    getBadgeColor(color) {
        return Wick.BloomreachWidget.badgeColorMap[color] || color;
    },

    hasRecommendations(payloadData) {
        if (Array.isArray(payloadData)) {
            return payloadData.length > 0;
        }

        return Boolean(
            payloadData &&
            Array.isArray(payloadData.recommendedProducts) &&
            payloadData.recommendedProducts.length
        );
    },

    normalizePayload(payloadData) {
        if (Array.isArray(payloadData)) {
            return payloadData;
        }

        if (payloadData && Array.isArray(payloadData.recommendedProducts)) {
            return payloadData.recommendedProducts;
        }

        return [];
    },

    getDisplayPrice(product) {
        return product.price || product.displayPrice || {};
    },

    dispatchWidgetEvent(eventName, payload) {
        return new Promise(function (resolve, reject) {
            const eventDetail = { resolve, reject };
            const event = createEvent(eventName, payload, eventDetail);

            window.dispatchEvent(event);
        });
    },

    getProductImage(product, fallbackProduct) {
        const productImages = product.images || [];
        const fallbackImages = fallbackProduct ? fallbackProduct.images || [] : [];
        const images = productImages.length ? productImages : fallbackImages;

        return (
            images.find(function (item) {
                return item.format === 'product';
            }) ||
            images.find(function (item) {
                return item.imageType === 'PRIMARY';
            }) ||
            images[0] ||
            {}
        );
    },

    getDropdownOptions(product) {
        if (!product.variantOptions || !product.variantOptions.length) {
            return [];
        }

        return product.variantOptions.map(function (variantOption) {
            const qualifiers = variantOption.variantOptionQualifiers || [];

            const label = qualifiers
                .map(function (qualifier) {
                    return qualifier.value;
                })
                .join(', ');

            return {
                label,
                value: variantOption.code,
            };
        });
    },

    getSelectedDropdownLabel(options, selectedValue) {
        const selectedOption = options.find(function (option) {
            return option.value === selectedValue;
        });

        return selectedOption ? selectedOption.label : '';
    },

    handleBulkAddToCartResponse(response) {
        const bulkData = response && response.bulkAddToCartData;

        if (!bulkData) {
            return;
        }

        Wick.BloomreachWidget.toast.show({
            type: bulkData.messageType,
            text: bulkData.messageText,
        });
    },

    getBadge(product) {
        const promotion = product.potentialPromotions && product.potentialPromotions[0];
        const promotionAttributes = promotion && promotion.customAttributes;

        if (promotionAttributes && promotionAttributes.overlayText) {
            return {
                text: promotionAttributes.overlayText,
                textColor: Wick.BloomreachWidget.getBadgeColor(
                    promotionAttributes.overlayTextColor
                ),
                color: Wick.BloomreachWidget.getBadgeColor(
                    promotionAttributes.overlayBackgroundColor
                ),
            };
        }

        return product.badge;
    },

    getWasPriceFormatted(product) {
        const price = Wick.BloomreachWidget.getDisplayPrice(product);
        const wasPrice = price && price.wasPrice;

        if (wasPrice && wasPrice.formattedValue) {
            return wasPrice.formattedValue;
        }

        if (wasPrice) {
            return `${price.currencySymbol || '£'}${wasPrice}`;
        }

        return '';
    },

    getDisplayPriceExcVat(product) {
        return product.displayPriceExclusiveVat || product.priceExclusiveVat || null;
    },

    getExcVatWasPrice(product) {
        const display = product.displayPriceExclusiveVat;
        const raw = product.priceExclusiveVat;
        if (display && typeof display.wasPrice === 'number') return display.wasPrice;
        if (raw && typeof raw.wasPrice === 'number') return raw.wasPrice;
        return null;
    },

    getExcVatFormattedValue(displayPrice, product) {
        const excVat = product ? Wick.BloomreachWidget.getDisplayPriceExcVat(product) : null;
        if (excVat && excVat.formattedValue) {
            return excVat.formattedValue;
        }
        if (!displayPrice || typeof displayPrice.value !== 'number') {
            return displayPrice ? displayPrice.formattedValue || '' : '';
        }
        const vatRate = displayPrice.vatRatePercentage || 20;
        return Wick.BloomreachWidget.formatPrice(displayPrice.value / (1 + vatRate / 100));
    },

    getProductRenderData(product, index, options = {}) {
        const shouldShowDropdown = index !== 0;
        const dropdownOptions = shouldShowDropdown
            ? Wick.BloomreachWidget.getDropdownOptions(product)
            : [];
        const selectedDropdownValue = options.selectedDropdownValue || '';
        const selectedDropdownLabel = Wick.BloomreachWidget.getSelectedDropdownLabel(
            dropdownOptions,
            selectedDropdownValue
        );
        const displayPrice = Wick.BloomreachWidget.getDisplayPrice(product);
        const showFromPrice = Boolean(
            index !== 0 &&
            !selectedDropdownValue &&
            displayPrice &&
            displayPrice.priceType === 'FROM'
        );

        const wasPriceFormatted = Wick.BloomreachWidget.getWasPriceFormatted(product);
        const excVatFormattedValue = Wick.BloomreachWidget.getExcVatFormattedValue(
            displayPrice,
            product
        );
        const isSwitchVat = !!(window.ACC && window.ACC.app && window.ACC.app.isVatToggleAvailable);

        let excVatWasPriceFormatted = '';
        if (wasPriceFormatted) {
            const excVatWasPrice = Wick.BloomreachWidget.getExcVatWasPrice(product);
            if (excVatWasPrice !== null) {
                excVatWasPriceFormatted = Wick.BloomreachWidget.formatPrice(excVatWasPrice);
            } else if (typeof displayPrice.wasPrice === 'number') {
                const vatRate = displayPrice.vatRatePercentage || 20;
                excVatWasPriceFormatted = Wick.BloomreachWidget.formatPrice(
                    displayPrice.wasPrice / (1 + vatRate / 100)
                );
            }
        }

        return {
            ...product,
            badge: Wick.BloomreachWidget.getBadge(product),
            price: displayPrice,
            wasPriceFormatted,
            'switch-vat': isSwitchVat,
            incVatFormattedValue: displayPrice.formattedValue || '',
            excVatFormattedValue,
            incVatWasPriceFormatted: wasPriceFormatted,
            excVatWasPriceFormatted,
            showFromPrice,
            image:
                options.image ||
                Wick.BloomreachWidget.getProductImage(product, options.fallbackProduct),
            dropdownOptions: dropdownOptions.map(function (option) {
                return {
                    ...option,
                    selected: option.value === selectedDropdownValue,
                };
            }),
            checkboxId: `${product.code}-${index}`,
            dropdownError: options.dropdownError || false,
            checked: options.checked || false,
            selectedDropdownValue,
            selectedDropdownLabel,
        };
    },

    renderWidget($container, context) {
        const { widgetContent, widgetWrapper, completeCard, recommendationIndexAttr } =
            Wick.BloomreachWidget.el;

        const $content = $container.find(widgetContent);
        const recommendations = Wick.BloomreachWidget.normalizePayload(context);

        if (!$content.length || !recommendations.length) {
            return;
        }

        Wick.BloomreachWidget.recommendations = recommendations;

        $content.html(completeWrapperTemplate());

        const $wrapper = $content.find(widgetWrapper);

        Wick.BloomreachWidget.dropdownCurrent = {};

        recommendations.forEach(function (recommendation, index) {
            const product = Wick.BloomreachWidget.getProductRenderData(
                recommendation.baseProduct,
                index
            );

            $wrapper.append(completeCardTemplate(product));

            const $card = $wrapper.children(completeCard).last();

            $card.attr(recommendationIndexAttr, index);

            if (index === 0 && recommendations.length > 1) {
                $wrapper.append(completeDividerTemplate());
            }
        });

        const isSwitchVat = !!(window.ACC && window.ACC.app && window.ACC.app.isVatToggleAvailable);
        $content.append(completeSummaryTemplate({ 'switch-vat': isSwitchVat }));
    },

    renderWidgetFromPayload(payloadData) {
        const { widgetContainer, completeWidget } = Wick.BloomreachWidget.el;
        const $containers = $(widgetContainer);

        if (!$containers.length) {
            return;
        }

        if (!Wick.BloomreachWidget.hasRecommendations(payloadData)) {
            $containers.find(completeWidget).hide();
            return;
        }

        $containers.each(function () {
            const $container = $(this);

            Wick.BloomreachWidget.renderWidget($container, payloadData);
            Wick.BloomreachWidget.initRenderedWidget($container);
        });
    },

    drawRating($root) {
        const $ratingOverlay = $root.find('.rating-overlay');

        $ratingOverlay.each(function () {
            let rating = parseFloat($(this).attr('data-rating')) || 0;
            const $stars = $(this).children(Wick.BloomreachWidget.el.starOverlay);

            $stars.each(function () {
                const $star = $(this);

                if (rating >= 1) {
                    rating--;
                } else if (rating > 0) {
                    const width = Math.asin(2 * rating - 1) / Math.PI + 0.5;
                    $star.css('width', width + 'rem');
                    rating = 0;
                } else {
                    $star.css('width', '0rem');
                }
            });
        });
    },

    getDropdownCard($dropdown) {
        return $dropdown.closest(Wick.BloomreachWidget.el.completeCard);
    },

    getDropdownCheckbox($dropdown) {
        return Wick.BloomreachWidget.getDropdownCard($dropdown).find(
            Wick.BloomreachWidget.el.cardCheckbox
        );
    },

    setDropdownCheckboxState($dropdown, isChecked, shouldTriggerChange = true) {
        const $checkbox = Wick.BloomreachWidget.getDropdownCheckbox($dropdown);

        if (!$checkbox.length) {
            return;
        }

        $checkbox.prop('checked', isChecked);

        if (shouldTriggerChange) {
            $checkbox.trigger('change');
        }
    },

    setDropdownError($dropdown, hasError) {
        $dropdown.toggleClass(Wick.BloomreachWidget.el.dropdownErrorClass, hasError);
    },

    validateDropdown($dropdown, options = {}) {
        const isValid = Boolean($dropdown.data(Wick.BloomreachWidget.el.selectedValueData));

        Wick.BloomreachWidget.setDropdownError($dropdown, !isValid);

        if (!isValid && options.uncheck) {
            Wick.BloomreachWidget.setDropdownCheckboxState($dropdown, false, false);
            Wick.BloomreachWidget.getDropdownCard($dropdown).removeClass(
                Wick.BloomreachWidget.el.selectedClass
            );
        }

        return isValid;
    },

    validateCardDropdown($card, options = {}) {
        const $dropdown = $card.find(Wick.BloomreachWidget.el.dropdownRoot);

        if (!$dropdown.length) {
            return true;
        }

        return Wick.BloomreachWidget.validateDropdown($dropdown, options);
    },

    findVariantProduct(recommendation, selectedValue) {
        if (!recommendation.variantProducts || !recommendation.variantProducts.length) {
            return null;
        }

        return recommendation.variantProducts.find(function (variantProduct) {
            return String(variantProduct.code) === String(selectedValue);
        });
    },

    getCardQuantity($card) {
        const $input = $card.find(Wick.BloomreachWidget.el.quantityInput);
        const quantity = parseInt($input.val(), 10);

        return Number.isNaN(quantity) ? 1 : quantity;
    },

    getCardProduct($card) {
        const { recommendationIndexAttr, dropdownRoot, selectedValueData } =
            Wick.BloomreachWidget.el;

        const recommendationIndex = Number($card.attr(recommendationIndexAttr));
        const recommendation = Wick.BloomreachWidget.recommendations[recommendationIndex];

        if (!recommendation) {
            return null;
        }

        const $dropdown = $card.find(dropdownRoot);
        const selectedValue = $dropdown.length ? $dropdown.data(selectedValueData) : '';

        if (selectedValue) {
            return (
                Wick.BloomreachWidget.findVariantProduct(recommendation, selectedValue) ||
                recommendation.baseProduct
            );
        }

        return recommendation.baseProduct;
    },

    getSelectedEntries($root) {
        const { completeCard, cardCheckbox } = Wick.BloomreachWidget.el;
        const entries = [];

        $root.find(completeCard).each(function () {
            const $card = $(this);
            const $checkbox = $card.find(cardCheckbox);

            if (!$checkbox.prop('checked')) {
                return;
            }

            const product = Wick.BloomreachWidget.getCardProduct($card);

            if (!product) {
                return;
            }

            entries.push({
                product,
                quantity: Wick.BloomreachWidget.getCardQuantity($card),
            });
        });

        return entries;
    },

    getAddToCartEntries($root) {
        return Wick.BloomreachWidget.getSelectedEntries($root).map(function (entry) {
            return {
                productCode: entry.product.code,
                quantity: entry.quantity,
            };
        });
    },

    updateSummary($root, response = {}) {
        const totalPriceExclusiveVat = response.totalPriceExclusiveVat || response.totalExcVatPrice;

        const totalWasPriceExclusiveVat =
            response.totalWasPriceExclusiveVat || response.totalExcVatWasPrice;

        const {
            summaryPriceValue,
            summarySalePrice,
            summaryPriceInc,
            summaryPriceExc,
            summarySalePriceInc,
            summarySalePriceExc,
        } = Wick.BloomreachWidget.el;

        Wick.BloomreachWidget.lastCalculationResponse = response;

        const $price = $root.find(summaryPriceValue);
        const $salePrice = $root.find(summarySalePrice);
        const $total = $root.find('.complete-widget__total');

        if (!$price.length) {
            return;
        }

        if (response.totalWasPrice) {
            $total.addClass('complete-widget__total-sale');
            const $priceInc = $price.find(summaryPriceInc);

            if ($priceInc.length) {
                $priceInc.text(response.totalWasPrice);
                $price
                    .find(summaryPriceExc)
                    .text(totalWasPriceExclusiveVat || response.totalWasPrice);

                $salePrice.find(summarySalePriceInc).text(response.totalPrice || '');
                $salePrice
                    .find(summarySalePriceExc)
                    .text(totalPriceExclusiveVat || response.totalPrice || '');
            } else {
                $price.text(response.totalWasPrice);
                $salePrice.text(response.totalPrice || '');
            }

            $salePrice.show();
            return;
        }

        $total.removeClass('complete-widget__total-sale');
        const $priceInc = $price.find(summaryPriceInc);
        if ($priceInc.length) {
            $priceInc.text(response.totalPrice || '£0.00');
            $price
                .find(summaryPriceExc)
                .text(totalPriceExclusiveVat || response.totalPrice || '£0.00');

            $salePrice.find(summarySalePriceInc).text('');
            $salePrice.find(summarySalePriceExc).text('');
            $salePrice.hide();
        } else {
            $price.text(response.totalPrice || '£0.00');
            $salePrice.text('').hide();
        }
    },

    updateCta($root) {
        const { ctaButton, cardCheckbox } = Wick.BloomreachWidget.el;
        const selectedCount = $root.find(cardCheckbox).filter(':checked').length;
        const $cta = $root.find(ctaButton);

        if (!$cta.length) {
            return;
        }

        $cta.prop('disabled', !selectedCount);
        Wick.BloomreachWidget.setCtaText($cta, Wick.BloomreachWidget.getCtaText(selectedCount));
    },

    dispatchCalculateTotal($root) {
        Wick.BloomreachWidget.updateCta($root);

        return Wick.BloomreachWidget.dispatchWidgetEvent(
            Wick.BloomreachWidget.CALCULATE_PRODUCT_BUNDLE_TOTAL_EVENT,
            {
                entries: Wick.BloomreachWidget.getSelectedEntries($root),
            }
        ).then(function (response) {
            Wick.BloomreachWidget.updateSummary($root, response);
        });
    },

    dispatchAddToCart($root, $button) {
        Wick.BloomreachWidget.loadingButton.start($button);

        return new Promise(function (resolve, reject) {
            let timeoutId;

            const cleanup = function () {
                window.removeEventListener('productAddedToCart', onProductAddedToCart);
                window.clearTimeout(timeoutId);
            };

            const onProductAddedToCart = function (event) {
                const response = event.detail || {};

                if (!response.bulkAddToCartData) {
                    return;
                }

                cleanup();
                resolve(response);
            };

            window.addEventListener('productAddedToCart', onProductAddedToCart);

            timeoutId = window.setTimeout(function () {
                cleanup();
                reject();
            }, 10000);

            window.dispatchEvent(
                new CustomEvent(Wick.BloomreachWidget.ADD_PRODUCT_BUNDLE_TO_CART_EVENT, {
                    detail: {
                        entries: Wick.BloomreachWidget.getAddToCartEntries($root),
                        reject: function (error) {
                            cleanup();
                            reject(error);
                        },
                    },
                })
            );
        })
            .then(function (response) {
                Wick.BloomreachWidget.handleBulkAddToCartResponse(response);
            })
            .catch(function () {
                Wick.BloomreachWidget.handleBulkAddToCartResponse({
                    bulkAddToCartData: {
                        messageType: 'error',
                        messageText: 'Selected product(s) were not added to basket',
                    },
                });
            })
            .finally(function () {
                Wick.BloomreachWidget.loadingButton.stop($button);
                Wick.BloomreachWidget.updateCta($root);
            });
    },

    reinitCard($card) {
        const { countBtn, completeWidget } = Wick.BloomreachWidget.el;

        $card.find(countBtn).remove();

        Wick.BloomreachWidget.initQuantityFields($card);
        Wick.BloomreachWidget.drawRating($card);
        Wick.BloomreachWidget.alignCardBlocks($card.closest(completeWidget));
    },

    replaceCardWithBaseProduct($dropdown, options = {}) {
        const {
            completeCard,
            recommendationIndexAttr,
            dropdownRoot,
            dropdownErrorClass,
            cardCheckbox,
        } = Wick.BloomreachWidget.el;

        const $card = $dropdown.closest(completeCard);
        const recommendationIndex = Number($card.attr(recommendationIndexAttr));
        const recommendation = Wick.BloomreachWidget.recommendations[recommendationIndex];

        if (!recommendation || !recommendation.baseProduct) {
            return null;
        }

        const productData = Wick.BloomreachWidget.getProductRenderData(
            recommendation.baseProduct,
            recommendationIndex,
            {
                dropdownError: options.dropdownError || false,
                checked: false,
            }
        );

        const newCardHtml = completeCardTemplate(productData);
        const $newCard = $(newCardHtml);

        $newCard.attr(recommendationIndexAttr, recommendationIndex);

        if (options.dropdownError) {
            $newCard.find(dropdownRoot).addClass(dropdownErrorClass);
        }

        $card.replaceWith($newCard);

        $newCard.find(cardCheckbox).prop('checked', false);

        $newCard
            .find(Wick.BloomreachWidget.el.quantityInput)
            .val(1)
            .data(Wick.BloomreachWidget.el.previousQuantityData, 1)
            .removeData(Wick.BloomreachWidget.el.quantityReadyData)
            .removeData(Wick.BloomreachWidget.el.countStepperInitializedData);

        Wick.BloomreachWidget.reinitCard($newCard);

        return $newCard;
    },

    replaceCardWithVariant($dropdown, selectedValue) {
        const {
            completeCard,
            recommendationIndexAttr,
            selectedClass,
            dropdownRoot,
            selectedValueData,
            cardCheckbox,
        } = Wick.BloomreachWidget.el;

        const $card = $dropdown.closest(completeCard);
        const recommendationIndex = Number($card.attr(recommendationIndexAttr));
        const recommendation = Wick.BloomreachWidget.recommendations[recommendationIndex];

        if (!recommendation) {
            return null;
        }

        const variantProduct = Wick.BloomreachWidget.findVariantProduct(
            recommendation,
            selectedValue
        );

        if (!variantProduct) {
            return null;
        }

        const productData = Wick.BloomreachWidget.getProductRenderData(
            {
                ...variantProduct,
                variantOptions: recommendation.baseProduct.variantOptions,
            },
            recommendationIndex,
            {
                fallbackProduct: recommendation.baseProduct,
                checked: true,
                selectedDropdownValue: selectedValue,
            }
        );

        const newCardHtml = completeCardTemplate(productData);
        const $newCard = $(newCardHtml);

        $newCard.attr(recommendationIndexAttr, recommendationIndex);
        $newCard.addClass(selectedClass);

        const $newDropdown = $newCard.find(dropdownRoot);

        if ($newDropdown.length) {
            $newDropdown.data(selectedValueData, selectedValue);
        }

        $card.replaceWith($newCard);

        $newCard.find(cardCheckbox).prop('checked', true);

        $newCard
            .find(Wick.BloomreachWidget.el.quantityInput)
            .val(1)
            .data(Wick.BloomreachWidget.el.previousQuantityData, 1)
            .removeData(Wick.BloomreachWidget.el.quantityReadyData)
            .removeData(Wick.BloomreachWidget.el.countStepperInitializedData);

        Wick.BloomreachWidget.reinitCard($newCard);

        return $newCard;
    },

    handleDropdownSelect($dropdown, selectedValue) {
        const $card = $dropdown.closest(Wick.BloomreachWidget.el.completeCard);
        const recommendationIndex = $card.attr(Wick.BloomreachWidget.el.recommendationIndexAttr);
        const currentValue = Wick.BloomreachWidget.dropdownCurrent[recommendationIndex];

        if (`${currentValue}` === `${selectedValue}`) {
            return;
        }

        Wick.BloomreachWidget.dropdownCurrent[recommendationIndex] = selectedValue;

        const $completeWidget = $dropdown.closest(Wick.BloomreachWidget.el.completeWidget);
        const isPlaceholder = !selectedValue;

        if (isPlaceholder) {
            Wick.BloomreachWidget.setDropdownError($dropdown, true);
            Wick.BloomreachWidget.setDropdownCheckboxState($dropdown, false, false);
            Wick.BloomreachWidget.replaceCardWithBaseProduct($dropdown, {
                dropdownError: true,
            });

            if ($completeWidget.length) {
                Wick.BloomreachWidget.dispatchCalculateTotal($completeWidget);
            }

            return;
        }

        Wick.BloomreachWidget.setDropdownError($dropdown, false);
        Wick.BloomreachWidget.setDropdownCheckboxState($dropdown, true, false);
        Wick.BloomreachWidget.replaceCardWithVariant($dropdown, selectedValue);

        if ($completeWidget.length) {
            Wick.BloomreachWidget.dispatchCalculateTotal($completeWidget);
        }
    },

    bindDropdowns() {
        const {
            dropdownRoot,
            dropdownToggle,
            dropdownValue,
            dropdownOption,
            dropdownOpenClass,
            dropdownOptionSelectedClass,
        } = Wick.BloomreachWidget.el;

        Wick.BloomreachWidget.dropdown = createDropdown({
            root: dropdownRoot,
            toggle: dropdownToggle,
            value: dropdownValue,
            option: dropdownOption,
            openClass: dropdownOpenClass,
            selectedClass: dropdownOptionSelectedClass,
            namespace: 'bloomreachDropdown',
            onSelect($dropdown, $option, selectedValue) {
                Wick.BloomreachWidget.handleDropdownSelect($dropdown, selectedValue);
            },
        });

        Wick.BloomreachWidget.dropdown.bind();
    },

    bindCardSelection($root) {
        const { completeCard, cardCheckbox, selectedClass } = Wick.BloomreachWidget.el;

        const $firstCard = $root.find(completeCard).first();

        $firstCard.find(cardCheckbox).prop('checked', true);
        $firstCard.addClass(selectedClass);

        $root.off('change.bloomreachCardSelection', cardCheckbox);
        $root.on('change.bloomreachCardSelection', cardCheckbox, function () {
            const $checkbox = $(this);
            const $card = $checkbox.closest(completeCard);
            const $dropdown = $card.find(Wick.BloomreachWidget.el.dropdownRoot);

            if (
                !$checkbox.prop('checked') &&
                $dropdown.hasClass(Wick.BloomreachWidget.el.dropdownErrorClass)
            ) {
                $card.removeClass(selectedClass);
                return;
            }

            if (
                $checkbox.prop('checked') &&
                !Wick.BloomreachWidget.validateCardDropdown($card, {
                    uncheck: true,
                })
            ) {
                $checkbox.prop('checked', false);
                $card.removeClass(selectedClass);
                return;
            }

            $card.toggleClass(selectedClass, this.checked);

            Wick.BloomreachWidget.dispatchCalculateTotal($root);
        });
    },

    bindDropdownValidation($root) {
        const { cardCheckbox, completeCard } = Wick.BloomreachWidget.el;

        $root.off('click.bloomreachDropdownValidation', cardCheckbox);
        $root.on('click.bloomreachDropdownValidation', cardCheckbox, function () {
            const $checkbox = $(this);
            const $card = $checkbox.closest(completeCard);

            if (
                $checkbox.prop('checked') &&
                !Wick.BloomreachWidget.validateCardDropdown($card, {
                    uncheck: true,
                })
            ) {
                $checkbox.prop('checked', false);
                $card.removeClass(Wick.BloomreachWidget.el.selectedClass);
            }
        });
    },

    bindAddToCart($root) {
        const { ctaButton } = Wick.BloomreachWidget.el;

        $root.off('click.bloomreachAddToCart', ctaButton);
        $root.on('click.bloomreachAddToCart', ctaButton, function (event) {
            event.preventDefault();

            const $button = $(this);

            if (
                $button.prop('disabled') ||
                Wick.BloomreachWidget.loadingButton.isLoading($button)
            ) {
                return;
            }

            Wick.BloomreachWidget.dispatchAddToCart($root, $button);
        });
    },

    alignBlock(selector, $root) {
        const $els = $root.find(selector);

        $els.css('min-height', '');

        if (!$els.length || Wick.Responsive.getCurrentBreakpoint() !== 'up-lg') {
            return;
        }

        let maxHeight = 0;

        $els.each(function () {
            maxHeight = Math.max(maxHeight, $(this).height());
        });

        if (maxHeight > 0) {
            $els.css('min-height', maxHeight + 'px');
        }
    },

    alignCardBlocks($root) {
        const { titleEl, optionsEl } = Wick.BloomreachWidget.el;

        Wick.BloomreachWidget.alignBlock(titleEl, $root);
        Wick.BloomreachWidget.alignBlock(optionsEl, $root);
    },

    setInitialSummary($root) {
        const entries = Wick.BloomreachWidget.getSelectedEntries($root);
        const firstEntry = entries[0];

        if (!firstEntry || !firstEntry.product) {
            return;
        }

        const product = firstEntry.product;
        const displayPrice = Wick.BloomreachWidget.getDisplayPrice(product);
        const priceExcVat = Wick.BloomreachWidget.getDisplayPriceExcVat(product);
        const wasPriceFormatted = Wick.BloomreachWidget.getWasPriceFormatted(product);

        const excVatWasPriceRaw = Wick.BloomreachWidget.getExcVatWasPrice(product);
        const excVatWasPrice =
            excVatWasPriceRaw !== null
                ? Wick.BloomreachWidget.formatPrice(excVatWasPriceRaw)
                : null;

        Wick.BloomreachWidget.updateSummary($root, {
            totalPrice: displayPrice.formattedValue || '£0.00',
            totalWasPrice: wasPriceFormatted || null,
            totalPriceExclusiveVat: priceExcVat ? priceExcVat.formattedValue || '' : '',
            totalWasPriceExclusiveVat: excVatWasPrice,
        });
    },

    initQuantityField($root, inputSel) {
        const stepper = createCountStepper({
            inputSel,
            min: 1,
            onChange(qty, inputEl) {
                const $input = $(inputEl);
                const $card = $input.closest(Wick.BloomreachWidget.el.completeCard);
                const $completeWidget = $input.closest(Wick.BloomreachWidget.el.completeWidget);
                const $checkbox = $card.find(Wick.BloomreachWidget.el.cardCheckbox);
                const previousQuantity =
                    $input.data(Wick.BloomreachWidget.el.previousQuantityData) || 1;

                if (!$input.data(Wick.BloomreachWidget.el.quantityReadyData)) {
                    $input.data(Wick.BloomreachWidget.el.previousQuantityData, qty || 1);
                    return;
                }

                if (!Wick.BloomreachWidget.validateCardDropdown($card)) {
                    $input.val(previousQuantity);

                    const $minus = $card.find('.count-btn--minus');

                    if (previousQuantity <= 1) {
                        $minus.prop('disabled', true);
                    }

                    return;
                }

                $checkbox.prop('checked', true);
                $card.addClass(Wick.BloomreachWidget.el.selectedClass);

                $input.data(Wick.BloomreachWidget.el.previousQuantityData, qty);
                $input.trigger('change');

                if ($completeWidget.length) {
                    Wick.BloomreachWidget.dispatchCalculateTotal($completeWidget);
                }
            },
        });

        stepper.init($root);

        $root.find(inputSel).data(Wick.BloomreachWidget.el.quantityReadyData, true);

        Wick.BloomreachWidget.steppers.push(stepper);
    },

    initQuantityFields($root) {
        const {
            quantityInput,
            countStepperInitializedData,
            countStepperRoot,
            previousQuantityData,
        } = Wick.BloomreachWidget.el;

        $root.find(quantityInput).each(function () {
            const $input = $(this);

            if ($input.data(countStepperInitializedData)) {
                return;
            }

            const inputId = $input.attr('id');

            if (!inputId) {
                return;
            }

            $input.data(countStepperInitializedData, true);
            $input.data(previousQuantityData, parseInt($input.val(), 10) || 1);

            Wick.BloomreachWidget.initQuantityField(
                $input.closest(countStepperRoot),
                `#${inputId}`
            );
        });
    },

    formatPrice(value) {
        return new Intl.NumberFormat('en-GB', {
            style: 'currency',
            currency: 'GBP',
            minimumFractionDigits: 2,
            maximumFractionDigits: 2,
        }).format(value);
    },

    resetWidgetState($root) {
        $root.find(Wick.BloomreachWidget.el.cardCheckbox).prop('checked', false);

        $root
            .find(Wick.BloomreachWidget.el.completeCard)
            .removeClass(Wick.BloomreachWidget.el.selectedClass);

        $root
            .find(Wick.BloomreachWidget.el.quantityInput)
            .val(1)
            .data(Wick.BloomreachWidget.el.previousQuantityData, 1);
    },

    resetBackForwardState() {
        $(Wick.BloomreachWidget.el.completeWidget).each(function () {
            const $widget = $(this);

            Wick.BloomreachWidget.resetWidgetState($widget);
            Wick.BloomreachWidget.bindCardSelection($widget);
        });
    },

    initRenderedWidget($container) {
        if (!Wick.BloomreachWidget.toast) {
            Wick.BloomreachWidget.toast = createToast({
                template: notificationTemplate,
            });
        }
        if (!Wick.BloomreachWidget.loadingButton) {
            Wick.BloomreachWidget.loadingButton = createLoadingButton();
        }
        const $completeWidget = $container.find(Wick.BloomreachWidget.el.completeWidget);

        if (!$completeWidget.length) {
            return;
        }

        Wick.BloomreachWidget.drawRating($completeWidget);
        Wick.BloomreachWidget.bindCardSelection($completeWidget);
        Wick.BloomreachWidget.bindDropdowns();
        Wick.BloomreachWidget.bindDropdownValidation($completeWidget);
        Wick.BloomreachWidget.bindAddToCart($completeWidget);
        Wick.BloomreachWidget.initQuantityFields($completeWidget);

        $completeWidget
            .find(Wick.BloomreachWidget.el.dropdownRoot)
            .removeClass(Wick.BloomreachWidget.el.dropdownErrorClass);

        Wick.BloomreachWidget.alignCardBlocks($completeWidget);
        Wick.BloomreachWidget.updateCta($completeWidget);
        Wick.BloomreachWidget.setInitialSummary($completeWidget);
    },

    init(payloadData) {
        const $containers = $(Wick.BloomreachWidget.el.widgetContainer);

        if (!payloadData || !Wick.BloomreachWidget.hasRecommendations(payloadData)) {
            $containers.find(Wick.BloomreachWidget.el.completeWidget).hide();
            return;
        }

        Wick.BloomreachWidget.renderWidgetFromPayload(payloadData);
    },
};

$(document).ready(function () {
    Wick.Responsive.onResize(function () {
        $(Wick.BloomreachWidget.el.widgetContainer).each(function () {
            const $completeWidget = $(this).find(Wick.BloomreachWidget.el.completeWidget);

            if ($completeWidget.length) {
                Wick.BloomreachWidget.alignCardBlocks($completeWidget);
            }
        });
    });
});

window.addEventListener('pagehide', function () {
    Wick.BloomreachWidget.resetBackForwardState();
});
