<template>
    <div class="miniBasket">
        <a
            :href="basketUrl"
            class="button actionButton basketButton"
            title="View basket"
            @click="openMiniBasket($event)"
        >
            <span class="visuallyHidden">View Basket</span>
            <i class="svgIcon">
                <svg xmlns="http://www.w3.org/2000/svg" width="29" height="26" viewBox="0 0 29 26" fill="none">
                    <path d="M12.9643 2.38739L8.96072 10.0039H20.3367L16.3331 2.38739C16.0402 1.8015 16.2843 1.06914 16.8214 0.776199C17.4073 0.483255 18.1396 0.727375 18.4326 1.26444L22.9732 10.0039H27.1721C28.0021 10.0039 28.7344 10.7363 28.7344 11.5663C28.7344 12.4451 28.0021 13.1287 27.1721 13.1287L24.6332 23.2841C24.2915 24.6511 23.022 25.6276 21.6061 25.6276H7.74012C6.2754 25.6276 5.0548 24.6511 4.66421 23.2841L2.17418 13.1287C1.29535 13.1287 0.611816 12.4451 0.611816 11.5663C0.611816 10.7363 1.29535 10.0039 2.17418 10.0039H6.32423L10.8649 1.26444C11.1578 0.727375 11.8902 0.483255 12.476 0.776199C13.0131 1.06914 13.2572 1.8015 12.9643 2.38739ZM9.98603 15.4722C9.98603 15.0816 9.59543 14.691 9.20484 14.691C8.76543 14.691 8.42366 15.0816 8.42366 15.4722V20.1593C8.42366 20.5987 8.76543 20.9405 9.20484 20.9405C9.59543 20.9405 9.98603 20.5987 9.98603 20.1593V15.4722ZM14.6731 14.691C14.2337 14.691 13.8919 15.0816 13.8919 15.4722V20.1593C13.8919 20.5987 14.2337 20.9405 14.6731 20.9405C15.0637 20.9405 15.4543 20.5987 15.4543 20.1593V15.4722C15.4543 15.0816 15.0637 14.691 14.6731 14.691ZM20.9226 15.4722C20.9226 15.0816 20.532 14.691 20.1414 14.691C19.702 14.691 19.3602 15.0816 19.3602 15.4722V20.1593C19.3602 20.5987 19.702 20.9405 20.1414 20.9405C20.532 20.9405 20.9226 20.5987 20.9226 20.1593V15.4722Z" fill="currentColor"/>
                </svg>
            </i>
            <span v-html="itemCount" class="totalQty" v-if="itemCount > 0" v-cloak></span>
        </a>

        <div class="miniBasketFlyout" :class="[open ? 'isOpen' : '']" v-if="minibasketEnabled">
            <div class="innerMinibasket">
                <header class="minibasketHeader">
                    <h2>
                        Bag
                        <span class="bagCount">({{ itemCount }})</span>
                    </h2>

                    <button
                        type="button"
                        class="closeButton"
                        aria-label="Close mini basket"
                        @click.prevent="closeMiniBasket()"
                    >
                        <i class="far fa-times"></i>
                    </button>
                </header>

                <div class="minibasketContent">
                    <div class="minibasketLoginBanner" v-if="!isLoggedIn">
                        <i class="far fa-info-circle"></i>
                        <p>
                            If you have an account you can
                            <a :href="loginUrl">login here</a>
                            to checkout faster with your saved details
                        </p>
                    </div>
                    <!-- .minibasketLoginBanner -->

                    <ul class="miniBasketItems" v-if="basket.items?.length">
                        <div class="miniBasketErrors" v-if="limitErrors.length">
                            <div class="error" v-if="limitErrors.length">
                                You have exceeded the maximum allowed quantity on some of your items.
                            </div>
                            <!-- .error -->
                        </div>
                        <!-- .miniBasketErrors -->

                        <template v-for="(product, productKey) in basket.items">
                            <li :key="product.id">
                                <div class="basketCard">
                                    <div class="cardImage">
                                        <a
                                            :href="product.item_url"
                                            class="imageWrap"
                                            :title="'View ' + product.item_name"
                                        >
                                            <img
                                                :src="product.item_image"
                                                width="100"
                                                height="100"
                                                :alt="'Image of:' + product.item_name"
                                                v-if="product.item_image"
                                            />

                                            <img
                                                src="/sites/default/images/placeholders/no-image-items-thumb.png"
                                                width="100"
                                                height="100"
                                                alt="No image"
                                                v-else
                                            />
                                        </a>
                                        <!-- .imageWrap -->
                                    </div>
                                    <!-- .cardImage -->

                                    <div class="cardContent">
                                        <h4
                                            class="productTitle"
                                            v-text="product.item_name"
                                            v-if="product.item_name"
                                        ></h4>

                                        <div class="productCategory" v-if="product.category_name">
                                            {{ product.category_name }}
                                        </div>

                                        <div
                                            class="quantityStepper"
                                            :class="[limitErrors.indexOf(product.id) > -1 ? 'limitError' : '']"
                                            v-if="product.can_remove && !product.quantity_lock"
                                        >
                                            <button
                                                type="button"
                                                class="stepButton stepButtonMinus"
                                                :aria-label="(product.quantity > 1 ? 'Decrease quantity of ' : 'Remove ') + product.item_name"
                                                :disabled="loading"
                                                @click.prevent="decrementItem(productKey)"
                                            >
                                                <i class="far fa-minus"></i>
                                            </button>
                                            <span class="stepValue" v-html="product.quantity"></span>
                                            <button
                                                type="button"
                                                class="stepButton stepButtonPlus"
                                                :aria-label="'Increase quantity of ' + product.item_name"
                                                :disabled="loading || isAtMaxQuantity(product)"
                                                @click.prevent="incrementItem(productKey)"
                                            >
                                                <i class="far fa-plus"></i>
                                            </button>
                                        </div>
                                        <!-- .quantityStepper -->

                                        <div class="productQuantityStatic" v-else-if="product.quantity_lock">
                                            Quantity: <span v-html="product.quantity"></span>
                                        </div>
                                        <!-- .productQuantityStatic -->
                                    </div>
                                    <!-- .cardContent -->

                                    <div class="cardRight">
                                        <del
                                            class="priceWas"
                                            v-if="isOnSale(product)"
                                            v-html="formatPrice(product.original_price)"
                                        ></del>
                                        <span
                                            class="productPrice"
                                            :class="[isOnSale(product) ? 'onSale' : '']"
                                            v-html="formatPrice(product.item_price)"
                                        ></span>
                                    </div>
                                    <!-- .cardRight -->
                                </div>
                                <!-- .basketCard -->

                                <div class="cardError" v-if="limitErrors.indexOf(product.id) > -1">
                                    You have exceeded the maximum allowed quantity on this item.
                                </div>
                                <!-- .error -->

                                <div class="cardLimitInfo" v-else-if="showOrderLimitMessage(product)">
                                    Maximum {{ product.restriction_per_order }} per order
                                </div>
                                <!-- .cardLimitInfo -->
                            </li>
                        </template>

                        <li v-if="basket.coupon_deduct">
                            <div class="basketCard">
                                <div class="cardImage"></div>
                                <div class="cardContent">
                                    <h4 class="productTitle">Discount</h4>
                                </div>
                                <div class="cardRight">
                                    <span class="discountPrice" v-html="formatPrice(-basket.coupon_deduct)"></span>
                                </div>
                                <!-- .cardRight -->
                            </div>
                        </li>
                    </ul>

                    <div class="noItemsBasket" v-else>
                        <h5>Your basket is currently empty</h5>
                    </div>
                    <!-- .noItemsBasket -->
                </div>
                <!-- .minibasketContent -->

                <footer class="minibasketFooter" v-if="basket.items?.length">
                    <div class="footerSubtotal">
                        <span class="subtotalLabel">Subtotal</span>
                        <span class="subtotalValue" v-html="formatPrice(basket.cost_subtotal)"></span>
                    </div>
                    <!-- .footerSubtotal -->

                    <a
                        :href="basketUrl"
                        title="Continue to checkout"
                        class="button checkoutButton"
                        :class="[limitErrors.length ? 'buttonDisabled' : '']"
                    >
                        <span class="checkoutLabel">Continue to checkout</span>
                        <i class="far fa-long-arrow-right"></i>
                    </a>
                </footer>
            </div>
            <!-- .innerMinibasket -->

            <div class="loadingBox" :class="[loading ? 'isLoading' : '']">
                <loading-spinner
                    :loading="loading"
                    loading-text="Updating Basket"
                    :show-loading-text="true"
                ></loading-spinner>
            </div>
            <!-- .loadingBox -->
        </div>
        <!-- .miniBasketFlyout -->
    </div>
    <!-- .miniBasket -->
</template>

<script>
import { isUndefined } from 'lodash'
import axios from 'axios'

export default {
    name: 'mtcMinibasket',

    props: {
        basketUrl: {
            type: [String],
            default: () => {
                return ''
            },
        },
        basketAjaxUrl: {
            type: [String],
            default: () => {
                return ''
            },
        },
        setCurrency: {
            type: [String],
            default: () => {
                return 'GBP'
            },
        },
        minibasketEnabled: {
            type: [Boolean],
            default: () => {
                return false
            },
        },
        isLoggedIn: {
            type: [Boolean],
            default: () => {
                return false
            },
        },
        loginUrl: {
            type: [String],
            default: () => {
                return '/members/login'
            },
        },
    },

    data() {
        return {
            basket: {
                cost_subtotal: 0,
                items: [],
            },
            currency: false,
            currencies: {},
            loading: false,
            open: false,
        }
    },

    computed: {
        itemCount() {
            return this.basket.items?.length ?? 0
        },
        limitErrors() {
            const limitError = this.basket && this.basket.limit_error

            if (limitError && typeof limitError === 'object') {
                const itemErrorIDs = Object.keys(limitError).map((id) => {
                    return parseInt(id)
                })

                return itemErrorIDs
            }

            return []
        },
    },

    mounted() {
        this.onBasketUpdate = (payload) => {
            if (payload && payload.basket) {
                this.applyPayload(payload, true)
            } else {
                this.refreshBasket(true)
            }
        }

        EventBus.$on('receiveBasketUpdate', this.onBasketUpdate)
    },

    beforeDestroy() {
        if (this.onBasketUpdate) {
            EventBus.$off('receiveBasketUpdate', this.onBasketUpdate)
            this.onBasketUpdate = null
        }
    },

    created() {
        const bootstrap = window.__MINIBASKET_BOOTSTRAP__
        if (bootstrap && bootstrap.basket) {
            this.applyPayload(bootstrap, false)
            window.__MINIBASKET_BOOTSTRAP__ = null
        } else {
            this.refreshBasket()
        }
    },

    methods: {
        applyPayload(payload, open) {
            if (!payload || typeof payload !== 'object') {
                return
            }

            if (!isUndefined(payload.currencies)) {
                this.currencies = payload.currencies
            }

            if (payload.basket) {
                if (!payload.basket.limit_error || typeof payload.basket.limit_error !== 'object') {
                    payload.basket.limit_error = payload.basket.limit_error ? payload.basket.limit_error : {}
                }
                this.basket = payload.basket
            }

            this.loading = false

            this.$nextTick(() => {
                this.setCurrencyObject()
                if (open) {
                    this.openMiniBasket()
                }
            })
        },

        setCurrencyObject() {
            if (isUndefined(this.currencies[this.setCurrency])) {
                this.currency = false
                return false
            }

            let currency = this.currencies[this.setCurrency]

            for (const key in currency) {
                switch (key) {
                    case 'enabled':
                        currency[key] = currency[key] == '1'
                        break
                    case 'ratio':
                        currency[key] = parseFloat(currency[key])
                        break
                }
            }

            if (currency.enabled) {
                this.currency = currency
                return true
            } else {
                return false
            }
        },

        formatPrice(price, salePrice) {
            if (isUndefined(salePrice)) {
                salePrice = 0
            } else {
                salePrice = parseFloat(salePrice)
            }

            let floatPrice = parseFloat(price)

            if (isNaN(floatPrice)) {
                floatPrice = 0.0
            }

            if (salePrice < floatPrice && salePrice > 0) {
                floatPrice = salePrice
            }

            if (!this.currency) {
                return floatPrice.toFixed(2)
            }

            let priceConverted = floatPrice * this.currency.ratio
            return this.currency.symbol + priceConverted.toFixed(2)
        },

        isOnSale(product) {
            if (!product) {
                return false
            }
            const price = parseFloat(product.item_price) || 0
            const original = parseFloat(product.original_price) || 0
            return original > 0 && original > price
        },

        incrementItem(productKey) {
            const product = this.basket.items[productKey]
            if (this.isAtMaxQuantity(product)) {
                return
            }
            const current = parseInt(product.quantity, 10) || 0
            this.setQuantity(productKey, current + 1)
        },

        decrementItem(productKey) {
            const product = this.basket.items[productKey]
            const current = parseInt(product.quantity, 10) || 0
            const next = Math.max(0, current - 1)

            if (next === 0) {
                const name = product.item_name || 'this item'
                if (!window.confirm(`Remove ${name} from your basket?`)) {
                    return
                }
            }

            this.setQuantity(productKey, next)
        },

        isAtMaxQuantity(product) {
            if (!product) {
                return false
            }
            if (this.limitErrors.indexOf(product.id) > -1) {
                return true
            }
            const max = parseInt(product.restriction_per_order, 10) || 0
            const qty = parseInt(product.quantity, 10) || 0
            return max > 0 && qty >= max
        },

        showOrderLimitMessage(product) {
            if (!product) {
                return false
            }
            const max = parseInt(product.restriction_per_order, 10) || 0
            const qty = parseInt(product.quantity, 10) || 0
            return max > 0 && qty >= max
        },

        setQuantity(productKey, quantity) {
            const vm = this
            if (vm.loading) {
                return
            }

            const previousQuantity = vm.basket.items[productKey].quantity

            vm.loading = true
            vm.basket.items[productKey].quantity = quantity

            axios
                .post(
                    vm.basketAjaxUrl,
                    {
                        ajax: true,
                        action: 'update_qty',
                        basket: vm.basket,
                    },
                    {
                        headers: {
                            'Content-Type': 'application/x-www-form-urlencoded',
                        },
                    },
                )
                .then(function (response) {
                    if (response.data.status === 'ok') {
                        vm.basket = response.data.basket
                    }
                    vm.loading = false
                })
                .catch(function () {
                    if (vm.basket.items[productKey]) {
                        vm.basket.items[productKey].quantity = previousQuantity
                    }
                    vm.loading = false
                })
        },

        refreshBasket(open) {
            if (isUndefined(open)) {
                open = false
            }

            const vm = this
            vm.loading = true

            axios
                .get('/shop/checkout/ajax.php?action=get_basket&ajax')
                .then(function (response) {
                    if (response.data.status === 'ok') {
                        vm.applyPayload(response.data, open)
                        return
                    }

                    vm.loading = false

                    if (open) {
                        vm.openMiniBasket()
                    }
                })
                .catch(function () {
                    vm.loading = false

                    if (open) {
                        vm.openMiniBasket()
                    }
                })
        },

        closeMiniBasket() {
            this.open = false
        },

        openMiniBasket(event) {
            if (!isUndefined(event)) {
                event.preventDefault()
            }

            if (this.minibasketEnabled) {
                const isBasketOrCheckout = document.getElementById('checkout')

                if (isBasketOrCheckout) {
                    this.open = false
                } else {
                    this.open = true
                }
            } else {
                this.open = false
                window.location = this.basketUrl
            }
        },
    },
}
</script>

<style lang="less">
.miniBasket {
    position: relative;

    .miniBasketErrors {
        margin: 0 0 24px;
        padding: 0;

        .error {
            padding: 16px 24px !important;
            margin: 0 !important;
            .rems(14) !important;
            line-height: 1.5 !important;
        }
    }

    .cardError {
        color: var(--alert_color);
        margin: 0 0 12px;
        padding: 0 32px;
        .rems(12);
        line-height: 1.5;
    }

    .cardLimitInfo {
        color: var(--text_color_alt, #6d6d6d);
        .rems(12);
        line-height: 1.5;
    }

    .miniBasketFlyout {
        position: fixed;
        top: 0;
        bottom: 0;
        height: 100vh;
        width: 50vw;
        max-width: 498px;
        background: #fcfcfc;
        backdrop-filter: blur(10px);
        filter: drop-shadow(4px 4px 16px rgba(0, 0, 0, 0.24));
        z-index: 999999999;
        border-left: none;
        border-radius: 32px 0 0 32px;
        overflow: hidden;

        opacity: 0;
        visibility: hidden;
        pointer-events: none;
        transition:
            transform 600ms,
            opacity 300ms,
            visibility 300ms;

        right: ~'calc(0px - ((100vw - @{header_width}) / 2))';
        transform: translateX(100%);

        @media all and (max-width: 1628px) {
            right: -24px;
            width: 100%;
            max-width: 498px;
        }

        @media @flyout {
            max-width: 420px;
        }

        @media @mobile {
            width: 100vw;
            max-width: 100vw;
            left: 0;
            right: 0;
            filter: none;
            border-radius: 0;
        }

        &.isOpen {
            opacity: 1;
            visibility: visible;
            pointer-events: auto;
            transform: translateX(0);
            transition:
                transform 600ms,
                opacity 300ms,
                visibility 300ms;
        }

        .headerAssessment & {
            right: 0;
        }
    }

    .noItemsBasket {
        padding: 32px;
        height: 100%;
        width: 100%;
        display: flex;
        align-items: center;
        justify-content: center;

        h5 {
            text-align: center;
            margin: 0;
            padding: 0;
            .rems(20);
            line-height: 1.2em;
            color: var(--text_color);
        }
    }

    .innerMinibasket {
        display: flex;
        flex-direction: column;
        height: 100%;
        overflow: hidden;
        z-index: 2;
    }

    .loadingBox {
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        width: 100%;
        height: 100%;
        z-index: 3;
        background: rgba(255, 255, 255, 0.8);
        backdrop-filter: blur(10px);
        pointer-events: none;
        visibility: hidden;
        opacity: 0;
        transition:
            opacity 200ms linear,
            visibility 200ms linear;

        &.isLoading {
            visibility: visible;
            opacity: 1;
            transition:
                opacity 200ms linear,
                visibility 200ms linear;
        }

        .loadingSpinner {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);

            .loadingText {
                margin-top: -24px;
            }
        }
    }

    .minibasketHeader {
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 32px;
        flex: 0 0 auto;
        position: relative;

        & > h2 {
            font-family: var(--primary_font);
            .rems(18);
            line-height: 1.5;
            font-weight: 600;
            color: var(--text_color);
            margin: 0;
            padding: 0;

            .bagCount {
                font-weight: 600;
                color: var(--text_color_alt, #6d6d6d);
                padding-left: 4px;
            }
        }

        .closeButton {
            border: none;
            background: transparent;
            color: var(--text_color);
            width: 44px;
            height: 44px;
            margin: 0;
            padding: 0;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: color 200ms linear;
            cursor: pointer;

            i {
                .rems(16);
                line-height: 1;
            }

            &:hover,
            &:active,
            &:focus-visible {
                color: var(--highlight_color);
                transition: color 200ms linear;
            }
        }
    }

    .minibasketContent {
        flex: 1 1 0;
        min-height: 0;
        width: 100%;
        display: flex;
        flex-direction: column;
        gap: 24px;
        padding: 16px 32px;
        overflow-x: hidden;
        overflow-y: auto;
    }

    .minibasketLoginBanner {
        display: flex;
        align-items: center;
        gap: 16px;
        padding: 16px;
        background: var(--border_color_subtle, #f5f5f5);
        border-radius: 8px;
        color: var(--text_color);
        .rems(16);
        line-height: 1.5;

        & > i {
            flex: 0 0 16px;
            .rems(16);
            line-height: 1;
            text-align: center;
        }

        p {
            margin: 0;
            padding: 0;
            flex: 1 1 auto;
        }

        a {
            font-weight: 700;
            color: inherit;
            text-decoration: underline;

            &:hover,
            &:focus-visible {
                color: var(--highlight_color);
            }
        }
    }

    .miniBasketItems {
        float: none;
        clear: both;
        margin: 0;
        padding: 0;
        list-style: none;
        background: transparent;

        &:before,
        &:after {
            display: none;
        }

        li {
            padding: 0;

            & + li {
                margin-top: 24px;
            }
        }
    }

    .basketCard {
        display: flex;
        align-items: flex-start;
        gap: 16px;
        padding: 0;

        .cardImage {
            flex: 0 0 101px;
        }

        .cardContent {
            flex: 1 1 auto;
            min-width: 0;
            display: flex;
            flex-direction: column;
            gap: 12px;
            padding: 0;
        }

        .cardRight {
            flex: 0 0 auto;
            display: flex;
            flex-direction: column;
            align-items: flex-end;

            .productPrice {
                .rems(18);
                line-height: 1.5;
                font-weight: 400;
                color: var(--text_color);

                &.onSale {
                    color: var(--alert_color);
                    font-weight: 600;
                }
            }

            .priceWas {
                .rems(14);
                line-height: 1.5;
                color: var(--text_color_alt, #6d6d6d);
                text-decoration: line-through;
            }

            .discountPrice {
                .rems(18);
                line-height: 1.5;
                font-weight: 400;
            }
        }

        .imageWrap {
            display: block;
            width: 101px;
            height: 98px;
            margin: 0;
            padding: 0;
            position: relative;
            overflow: hidden;
            background: linear-gradient(167.5deg, #f3f3f3 12%, #dfdfdf 97%);
            border-radius: 8px;

            img {
                width: 100%;
                height: 100%;
                object-fit: contain;
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
            }
        }

        .productTitle {
            font-family: var(--primary_font);
            .rems(18);
            line-height: 1.5;
            font-weight: 600;
            margin: 0;
            padding: 0;
            color: var(--text_color);
        }

        .productCategory {
            .rems(16);
            line-height: 1.5;
            color: var(--text_color_alt, #6d6d6d);
            margin-top: -10px;
        }

        .productQuantityStatic {
            .rems(14);
            line-height: 1.5;
            font-weight: 600;
            color: var(--text_color);
            align-self: flex-start;
        }

        .quantityStepper {
            display: inline-flex;
            align-items: center;
            border: 1px solid var(--border_color, #e6e6e6);
            background: #fcfcfc;
            border-radius: 40px;
            padding: 0 4px;
            align-self: flex-start;

            &.limitError {
                border-color: var(--alert_color);
                color: var(--alert_color);
            }

            .stepButton {
                background: transparent;
                border: none;
                cursor: pointer;
                width: 24px;
                height: 24px;
                padding: 6px;
                display: flex;
                align-items: center;
                justify-content: center;
                color: var(--text_color);
                .rems(12);
                line-height: 1.5;
                transition:
                    color 200ms linear,
                    opacity 200ms linear;

                i {
                    .rems(12);
                    line-height: 1;
                }

                &:hover:not(:disabled),
                &:focus-visible:not(:disabled) {
                    color: var(--highlight_color);
                }

                &:disabled {
                    opacity: 0.4;
                    cursor: not-allowed;
                }
            }

            .stepValue {
                .rems(14);
                line-height: 1.5;
                font-weight: 600;
                color: var(--text_color);
                min-width: 20px;
                padding: 6px 0;
                text-align: center;
            }
        }
    }

    .minibasketFooter {
        padding: 32px;
        flex: 0 0 auto;
        display: flex;
        flex-direction: column;
        gap: 16px;
        border-top: 1px solid var(--border_color, #e6e6e6);
        background: #fcfcfc;

        .footerSubtotal {
            display: flex;
            align-items: center;
            justify-content: space-between;
            .rems(18);
            line-height: 1.5;
            font-weight: 700;
            color: var(--text_color);

            .subtotalLabel,
            .subtotalValue {
                display: inline-block;
            }
        }

        .checkoutButton {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            margin: 0;
            width: 100%;
            padding: 16px 24px;
            border-radius: 12px;

            &.buttonDisabled {
                opacity: 0.5 !important;
                pointer-events: none !important;
            }

            .checkoutLabel {
                .rems(18);
                line-height: 1.5;
                font-weight: 400;
            }

            i {
                .rems(18);
                line-height: 1;
            }
        }
    }
}
</style>
