(function () {

    'use strict';


    function initialiseAllReviews(context) {

        context = context || document;

        const widgets =
            context.querySelectorAll(
                '.stech-google-reviews:not([data-stech-initialised])'
            );


        widgets.forEach(
            function (widget) {

                widget.setAttribute(
                    'data-stech-initialised',
                    'true'
                );

                initialiseReviews(
                    widget
                );
            }
        );
    }


    async function initialiseReviews(widget) {

        const endpoint =
            widget.dataset.endpoint;

        const limit =
            parseInt(
                widget.dataset.limit || '5',
                10
            );

        const excerptLength =
            parseInt(
                widget.dataset.excerpt || '135',
                10
            );


        const loading =
            widget.querySelector(
                '.stech-reviews-loading'
            );

        const errorBox =
            widget.querySelector(
                '.stech-reviews-error'
            );

        const summary =
            widget.querySelector(
                '.stech-reviews-summary'
            );

        const carouselWrap =
            widget.querySelector(
                '.stech-reviews-carousel-wrap'
            );

        const footer =
            widget.querySelector(
                '.stech-reviews-footer'
            );


        if (!endpoint) {

            showError(
                loading,
                errorBox,
                'Google Reviews endpoint is missing.'
            );

            return;
        }


        try {

            const response =
                await fetch(
                    endpoint,
                    {
                        method: 'GET',
                        credentials: 'same-origin',
                        headers: {
                            'Accept': 'application/json'
                        }
                    }
                );


            if (!response.ok) {

                throw new Error(
                    'Google Reviews API returned HTTP ' +
                    response.status
                );
            }


            const data =
                await response.json();


            if (!data.success) {

                throw new Error(
                    data.message ||
                    'Unable to load Google reviews.'
                );
            }


            renderSummary(
                widget,
                data.business || {}
            );


            const reviews =
                Array.isArray(data.reviews)
                    ? data.reviews.slice(
                        0,
                        limit
                    )
                    : [];


            if (reviews.length > 0) {

                renderReviews(
                    widget,
                    reviews,
                    excerptLength
                );

            } else {

                renderNoReviews(
                    widget
                );
            }


            if (carouselWrap) {
                carouselWrap.hidden = false;
            }


            if (summary) {
                summary.hidden = false;
            }


            if (footer) {
                footer.hidden = false;
            }


            if (loading) {
                loading.hidden = true;
            }


            setupFooter(
                widget,
                data.business || {}
            );


            setupCarousel(
                widget
            );


        } catch (error) {

            console.error(
                'S-Tech Google Reviews:',
                error
            );


            showError(
                loading,
                errorBox,
                error.message ||
                'Unable to load Google reviews.'
            );
        }
    }


    function showError(
        loading,
        errorBox,
        message
    ) {

        if (loading) {
            loading.hidden = true;
        }


        if (errorBox) {

            errorBox.hidden =
                false;

            errorBox.textContent =
                message;
        }
    }


    function renderSummary(
        widget,
        business
    ) {

        const name =
            business.name || '';

        const rating =
            Number(
                business.rating || 0
            );

        const total =
            Number(
                business.total_reviews || 0
            );


        const businessName =
            widget.querySelector(
                '.stech-business-name'
            );

        const ratingElement =
            widget.querySelector(
                '.stech-overall-rating'
            );

        const starsElement =
            widget.querySelector(
                '.stech-overall-stars'
            );

        const totalElement =
            widget.querySelector(
                '.stech-total-reviews'
            );

        const mapsBrand =
            widget.querySelector(
                '.stech-google-maps-brand'
            );


        if (businessName) {
            businessName.textContent =
                name;
        }


        if (ratingElement) {
            ratingElement.textContent =
                rating.toFixed(1);
        }


        if (starsElement) {

            starsElement.innerHTML =
                createStars(
                    rating
                );
        }


        if (totalElement) {

            totalElement.textContent =
                total +
                (
                    total === 1
                        ? ' Google review'
                        : ' Google reviews'
                );
        }


        if (
            mapsBrand &&
            business.google_maps_uri
        ) {

            mapsBrand.href =
                business.google_maps_uri;

            mapsBrand.hidden =
                false;
        }
    }


    function renderReviews(
        widget,
        reviews,
        excerptLength
    ) {

        const track =
            widget.querySelector(
                '.stech-reviews-track'
            );


        if (!track) {
            return;
        }


        track.innerHTML =
            reviews
                .map(
                    function (review) {

                        return createReviewCard(
                            review,
                            excerptLength
                        );
                    }
                )
                .join('');


        setupReadMore(
            track
        );
    }


    function renderNoReviews(widget) {

        const track =
            widget.querySelector(
                '.stech-reviews-track'
            );


        if (!track) {
            return;
        }


        track.innerHTML = `
            <div class="stech-no-reviews">
                No Google review cards are currently available.
            </div>
        `;
    }


    function createReviewCard(
        review,
        excerptLength
    ) {

        const author =
            String(
                review.author_name ||
                'Google User'
            );


        const rawText =
            String(
                review.text || ''
            );


        const time =
            String(
                review.relative_time ||
                ''
            );


        const rating =
            Number(
                review.rating || 0
            );


        const photo =
            safeUrl(
                review.author_photo || ''
            );


        const authorUri =
            safeUrl(
                review.author_uri || ''
            );


        const safeAuthor =
            escapeHtml(
                author
            );


        const safeTime =
            escapeHtml(
                time
            );


        const initial =
            escapeHtml(
                author
                    .charAt(0)
                    .toUpperCase()
            );


        const shortText =
            createExcerpt(
                rawText,
                excerptLength
            );


        const needsExcerpt =
            shortText.length <
            rawText.length;


        let avatarHtml = '';


        if (photo) {

            avatarHtml = `
                <img
                    class="stech-review-avatar"
                    src="${photo}"
                    alt="${safeAuthor}"
                    loading="lazy"
                >
            `;

        } else {

            avatarHtml = `
                <div
                    class="
                        stech-review-avatar
                        stech-review-avatar-placeholder
                    "
                    aria-hidden="true"
                >
                    ${initial}
                </div>
            `;
        }


        if (authorUri) {

            avatarHtml = `
                <a
                    href="${authorUri}"
                    target="_blank"
                    rel="noopener noreferrer"
                    class="stech-review-avatar-link"
                >
                    ${avatarHtml}
                </a>
            `;
        }


        const authorHtml =
            authorUri
                ? `
                    <a
                        href="${authorUri}"
                        target="_blank"
                        rel="noopener noreferrer"
                        class="stech-review-author"
                    >
                        ${safeAuthor}
                    </a>
                `
                : `
                    <div
                        class="stech-review-author"
                    >
                        ${safeAuthor}
                    </div>
                `;


        const textHtml =
            needsExcerpt
                ? `
                    <div
                        class="stech-review-text"
                    >

                        <span
                            class="stech-review-short"
                        >
                            ${escapeHtml(shortText)}…
                        </span>

                        <span
                            class="stech-review-full"
                            hidden
                        >
                            ${escapeHtml(rawText)}
                        </span>

                    </div>

                    <button
                        type="button"
                        class="stech-review-expand"
                        aria-expanded="false"
                    >
                        Read more
                    </button>
                `
                : `
                    <div
                        class="stech-review-text"
                    >
                        ${escapeHtml(rawText)}
                    </div>
                `;


        return `
            <article
                class="stech-review-card"
            >

                <div
                    class="stech-review-header"
                >

                    ${avatarHtml}

                    <div
                        class="stech-review-author-meta"
                    >

                        ${authorHtml}

                        <div
                            class="stech-review-time"
                        >
                            ${safeTime}
                        </div>

                    </div>

                </div>


                <div
                    class="stech-review-stars"
                    aria-label="${rating} out of 5 stars"
                >
                    ${createStars(rating)}
                </div>


                ${textHtml}

            </article>
        `;
    }


    function createExcerpt(
        text,
        maximumLength
    ) {

        if (
            !text ||
            text.length <= maximumLength
        ) {
            return text;
        }


        let excerpt =
            text.substring(
                0,
                maximumLength
            );


        const lastSpace =
            excerpt.lastIndexOf(' ');


        if (
            lastSpace >
            maximumLength * 0.7
        ) {

            excerpt =
                excerpt.substring(
                    0,
                    lastSpace
                );
        }


        return excerpt.trim();
    }


    function setupReadMore(container) {

        const buttons =
            container.querySelectorAll(
                '.stech-review-expand'
            );


        buttons.forEach(
            function (button) {

                button.addEventListener(
                    'click',
                    function () {

                        const card =
                            button.closest(
                                '.stech-review-card'
                            );


                        if (!card) {
                            return;
                        }


                        const shortText =
                            card.querySelector(
                                '.stech-review-short'
                            );

                        const fullText =
                            card.querySelector(
                                '.stech-review-full'
                            );


                        if (
                            !shortText ||
                            !fullText
                        ) {
                            return;
                        }


                        const expanded =
                            button.getAttribute(
                                'aria-expanded'
                            ) === 'true';


                        if (expanded) {

                            fullText.hidden =
                                true;

                            shortText.hidden =
                                false;

                            button.textContent =
                                'Read more';

                            button.setAttribute(
                                'aria-expanded',
                                'false'
                            );

                        } else {

                            shortText.hidden =
                                true;

                            fullText.hidden =
                                false;

                            button.textContent =
                                'Show less';

                            button.setAttribute(
                                'aria-expanded',
                                'true'
                            );
                        }
                    }
                );
            }
        );
    }


    function setupFooter(
        widget,
        business
    ) {

        const viewButtons =
            widget.querySelectorAll(
                '.stech-view-google'
            );

        const writeButtons =
            widget.querySelectorAll(
                '.stech-write-review'
            );


        const mapsUrl =
            safeUrl(
                business.google_maps_uri ||
                ''
            );


        viewButtons.forEach(
            function (button) {

                if (mapsUrl) {

                    button.href =
                        mapsUrl;

                } else {

                    button.style.display =
                        'none';
                }
            }
        );


        writeButtons.forEach(
            function (button) {

                if (business.place_id) {

                    button.href =
                        'https://search.google.com/local/writereview?placeid=' +
                        encodeURIComponent(
                            business.place_id
                        );

                } else {

                    button.style.display =
                        'none';
                }
            }
        );
    }


    function setupCarousel(widget) {

        if (
            widget.classList.contains(
                'stech-google-reviews--grid'
            )
        ) {
            return;
        }


        const track =
            widget.querySelector(
                '.stech-reviews-track'
            );

        const prev =
            widget.querySelector(
                '.stech-carousel-prev'
            );

        const next =
            widget.querySelector(
                '.stech-carousel-next'
            );


        if (
            !track ||
            !prev ||
            !next
        ) {
            return;
        }


        function scrollAmount() {

            const card =
                track.querySelector(
                    '.stech-review-card'
                );


            if (!card) {
                return 320;
            }


            const styles =
                window.getComputedStyle(
                    track
                );


            const gap =
                parseFloat(
                    styles.columnGap ||
                    styles.gap ||
                    24
                );


            return (
                card.getBoundingClientRect()
                    .width +
                gap
            );
        }


        prev.addEventListener(
            'click',
            function () {

                track.scrollBy({
                    left:
                        -scrollAmount(),
                    behavior:
                        'smooth'
                });
            }
        );


        next.addEventListener(
            'click',
            function () {

                track.scrollBy({
                    left:
                        scrollAmount(),
                    behavior:
                        'smooth'
                });
            }
        );


        function updateButtons() {

            const maxScroll =
                track.scrollWidth -
                track.clientWidth;


            prev.disabled =
                track.scrollLeft <= 5;


            next.disabled =
                track.scrollLeft >=
                maxScroll - 5;
        }


        track.addEventListener(
            'scroll',
            function () {

                window.requestAnimationFrame(
                    updateButtons
                );
            }
        );


        window.addEventListener(
            'resize',
            updateButtons
        );


        setTimeout(
            updateButtons,
            100
        );
    }


    function createStars(rating) {

        const rounded =
            Math.round(
                Number(rating || 0)
            );


        let stars = '';


        for (
            let i = 1;
            i <= 5;
            i++
        ) {

            stars += `
                <span
                    class="${
                        i <= rounded
                            ? 'stech-star stech-star-active'
                            : 'stech-star'
                    }"
                    aria-hidden="true"
                >
                    ★
                </span>
            `;
        }


        return stars;
    }


    function escapeHtml(value) {

        const div =
            document.createElement(
                'div'
            );

        div.textContent =
            String(value ?? '');

        return div.innerHTML;
    }


    function safeUrl(value) {

        if (!value) {
            return '';
        }


        try {

            const url =
                new URL(
                    value,
                    window.location.origin
                );


            if (
                url.protocol !== 'http:' &&
                url.protocol !== 'https:'
            ) {
                return '';
            }


            return escapeHtml(
                url.href
            );


        } catch (error) {

            return '';
        }
    }


    if (
        document.readyState ===
        'loading'
    ) {

        document.addEventListener(
            'DOMContentLoaded',
            function () {

                initialiseAllReviews(
                    document
                );
            }
        );

    } else {

        initialiseAllReviews(
            document
        );
    }


    window.addEventListener(
        'elementor/frontend/init',
        function () {

            if (
                window.elementorFrontend &&
                window.elementorFrontend.hooks
            ) {

                window.elementorFrontend.hooks.addAction(
                    'frontend/element_ready/global',
                    function ($scope) {

                        const element =
                            $scope &&
                            $scope[0]
                                ? $scope[0]
                                : document;


                        initialiseAllReviews(
                            element
                        );
                    }
                );
            }
        }
    );


    const observer =
        new MutationObserver(
            function (mutations) {

                mutations.forEach(
                    function (mutation) {

                        mutation.addedNodes
                            .forEach(
                                function (node) {

                                    if (
                                        node.nodeType !==
                                        Node.ELEMENT_NODE
                                    ) {
                                        return;
                                    }


                                    if (
                                        node.matches &&
                                        node.matches(
                                            '.stech-google-reviews'
                                        )
                                    ) {

                                        initialiseAllReviews(
                                            node.parentNode ||
                                            document
                                        );

                                        return;
                                    }


                                    if (
                                        node.querySelector &&
                                        node.querySelector(
                                            '.stech-google-reviews'
                                        )
                                    ) {

                                        initialiseAllReviews(
                                            node
                                        );
                                    }
                                }
                            );
                    }
                );
            }
        );


    observer.observe(
        document.documentElement,
        {
            childList: true,
            subtree: true
        }
    );


})();