<template>
    <transition name="upsellsPopup">
        <div
            v-if="visible"
            class="upsellsPopup"
            role="dialog"
            aria-modal="true"
            :aria-label="title"
            @click.self="close"
        >
            <div class="upsellsPopup__dialog" ref="dialog" tabindex="-1">

                <button
                    type="button"
                    class="upsellsPopup__close"
                    aria-label="Close"
                    ref="closeBtn"
                    @click="close"
                >
                    <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false">
                        <path d="M6 6L18 18M18 6L6 18" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
                    </svg>
                </button>

                <div class="upsellsPopup__header">
                    <h2 class="upsellsPopup__title" v-text="title"></h2>
                    <p class="upsellsPopup__subtitle">Below are suggested add-on products based on your basket</p>
                </div> <!-- .upsellsPopup__header -->

                <div class="upsellsPopup__body">

                    <!-- Pinned confirmation row: the product just added. No add button. -->
                    <div class="upsellsPopup__pinned" v-if="addedProduct">
                        <div class="upsellsPopup__thumb">
                            <img
                                    v-if="pinnedImage"
                                    :src="pinnedImage"
                                    :alt="addedProduct.name"
                                    loading="lazy"
                            />
                        </div>
                        <div class="upsellsPopup__pinnedText">
                            <h3 class="upsellsPopup__rowName" v-text="addedProduct.name"></h3>
                        </div>
                        <span class="upsellsPopup__check" aria-label="Added to basket">
                            <svg width="22" height="22" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false">
                                <path d="M5 12.5L10 17.5L19 7.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
                            </svg>
                        </span>
                    </div> <!-- .upsellsPopup__pinned -->

                    <upsells-row
                            v-for="upsell in visibleUpsells"
                            :key="'upsell_' + upsell.id"
                            :upsell="upsell"
                            @added="onUpsellAdded"
                    ></upsells-row>

                </div> <!-- .upsellsPopup__body -->

                <div class="upsellsPopup__footer">
                    <button
                            type="button"
                            class="upsellsPopup__skip"
                            :class="{ 'upsellsPopup__skip--continue': hasAdded }"
                            @click="skip"
                    >{{ skipLabel }} &rsaquo;</button>
                </div> <!-- .upsellsPopup__footer -->

            </div> <!-- .upsellsPopup__dialog -->
        </div>
    </transition>
</template>

<script>
// Single global modal, placed once in layouts/assessment.twig (inside the
// #vue_environment root that main-app.js mounts on).
// Open from the assessment add-to-basket flow with:
//   window.EventBus.$emit('upsells:open', { addedProduct, upsells, proceedUrl })
import axios from 'axios';
import upsellsRow from './upsells_row.vue';

export default {
    name: 'UpsellsPopup',
    components: {
        upsellsRow,
    },
    data() {
        return {
            visible: false,
            title: 'Complete your basket',
            addedProduct: null,
            proceedUrl: null,
            rawUpsells: [],
            basketItemIds: [],
            hasAdded: false,
        };
    },
    computed: {
        // Hide upsells already in the basket (resolved live on open).
        visibleUpsells() {
            return this.rawUpsells.filter(upsell => this.basketItemIds.indexOf(Number(upsell.id)) === -1);
        },

        // Once the user has added an upsell, the footer action becomes the primary
        // "continue" CTA rather than a skip.
        skipLabel() {
            return this.hasAdded ? 'Continue to basket' : 'Skip & continue';
        },

        // The assessment product object carries images decorated with size variants
        // (images[].sizes[variant]); fall back defensively across shapes.
        pinnedImage() {
            const images = this.addedProduct && this.addedProduct.images;
            if (Array.isArray(images) && images.length) {
                const image = images.find(img => img.default) || images[0];
                const sizes = image.sizes || {};
                const variant = sizes.small || sizes.thumbs || sizes.large || Object.values(sizes)[0];
                if (variant) {
                    if (variant.displayImage) return variant.displayImage;
                    if (variant.path) return variant.path + image.name;
                }
            }
            return (this.addedProduct && this.addedProduct.image) || '';
        },
    },
    mounted() {
        this._onOpen = payload => this.open(payload);
        if (window.EventBus) {
            window.EventBus.$on('upsells:open', this._onOpen);
        }
    },
    beforeDestroy() {
        if (window.EventBus) {
            window.EventBus.$off('upsells:open', this._onOpen);
        }
        document.removeEventListener('keydown', this.onKeydown, true);
        this.unlockScroll();
    },
    methods: {
        open(payload) {
            // Re-entrant: a second product added while the overlay is open should
            // replace the current one, not be silently dropped.
            if (this.visible) {
                this.close();
            }

            payload = payload || {};
            this.addedProduct = payload.addedProduct || null;
            this.proceedUrl = payload.proceedUrl || null;
            this.rawUpsells = Array.isArray(payload.upsells) ? payload.upsells : [];
            this.hasAdded = false;
            this.previouslyFocused = document.activeElement;

            // Resolve current basket contents, then either show the overlay or —
            // if every upsell is already in the basket — proceed straight through.
            this.fetchBasketIds().then(ids => {
                this.basketItemIds = ids;
                if (!this.visibleUpsells.length) {
                    this.skip();
                    return;
                }
                this.show();
            });
        },

        onUpsellAdded() {
            // Surface the "Continue to basket" CTA once anything has been added.
            this.hasAdded = true;
        },

        fetchBasketIds() {
            return axios.get('/shop/checkout/ajax.php?action=get_basket&ajax')
                .then(response => {
                    const items = response.data && response.data.basket && response.data.basket.items;
                    if (!items) return [];
                    return Object.values(items)
                        .map(item => Number(item.item_id != null ? item.item_id : item.id))
                        .filter(id => !isNaN(id));
                })
                .catch(() => []);
        },

        show() {
            this.visible = true;
            this.lockScroll();
            document.addEventListener('keydown', this.onKeydown, true);
            this.$nextTick(() => {
                if (this.$refs.closeBtn) this.$refs.closeBtn.focus();
            });
        },

        close() {
            if (!this.visible) return;
            this.visible = false;
            this.unlockScroll();
            document.removeEventListener('keydown', this.onKeydown, true);
            if (this.previouslyFocused && this.previouslyFocused.focus) {
                this.previouslyFocused.focus();
            }
        },

        skip() {
            if (this.proceedUrl) {
                window.location = this.proceedUrl;
            } else {
                this.close();
            }
        },

        onKeydown(e) {
            if (e.key === 'Escape') {
                this.close();
                return;
            }
            if (e.key === 'Tab') this.trapFocus(e);
        },

        trapFocus(e) {
            const dialog = this.$refs.dialog;
            if (!dialog) return;
            const focusables = dialog.querySelectorAll(
                'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
            );
            if (!focusables.length) return;
            const first = focusables[0];
            const last = focusables[focusables.length - 1];
            if (e.shiftKey && document.activeElement === first) {
                e.preventDefault();
                last.focus();
            } else if (!e.shiftKey && document.activeElement === last) {
                e.preventDefault();
                first.focus();
            }
        },

        lockScroll() {
            document.documentElement.style.overflow = 'hidden';
        },

        unlockScroll() {
            document.documentElement.style.overflow = '';
        },
    },
};
</script>
