import { Controller } from '@hotwired/stimulus';
import { Splide } from '@splidejs/splide';
import '@splidejs/splide/css';

export default class extends Controller {
    splide = null;
    clickHandler = null;
    refreshHandler = null;
    paginationButtons = [];
    selectedIndex = 0;

    connect() {
        if (this.splide) {
            this.splide.destroy(true);
        }

        this.selectedIndex = this.getActiveSlideIndex();

        this.splide = new Splide(this.element, {
            type: 'slide',
            autoWidth: true,
            arrows: false,
            pagination: false,
            drag: true,
            trimSpace: false,
            omitEnd: false,
            waitForTransition: false,
            gap: '1rem',
            breakpoints: {
                1024: {
                    gap: '0.75rem',
                },
                767: {
                    /* focus: 'center',*/
                    padding: {
                        left: '1rem',
                        right: '1rem',
                    },
                },
            },
        });

        this.splide.on('mounted refreshed resized updated', () => {
            this.renderPagination();
            this.syncActiveSlidePosition();
        });

        this.splide.mount();
        this.renderPagination();
        this.queueRefresh();
        this.clickHandler = this.handleClick.bind(this);
        this.element.addEventListener('click', this.clickHandler);

        if (document.fonts?.ready) {
            this.refreshHandler = () => this.queueRefresh();
            document.fonts.ready.then(this.refreshHandler);
        }
    }

    disconnect() {
        if (this.clickHandler) {
            this.element.removeEventListener('click', this.clickHandler);
            this.clickHandler = null;
        }

        this.refreshHandler = null;

        if (this.splide) {
            this.splide.destroy(true);
            this.splide = null;
        }
    }

    handleClick(event) {
        const link = event.target.closest('[data-shop-tabs-link]');

        if (!link || !this.splide) {
            return;
        }

        const slide = link.closest('.splide__slide');
        const index = this.getSlideIndex(slide);

        this.selectSlide(slide, index);
    }

    queueRefresh() {
        requestAnimationFrame(() => {
            requestAnimationFrame(() => {
                if (this.splide) {
                    this.splide.refresh();
                }
            });
        });
    }

    getActiveSlideIndex() {
        const slides = Array.from(this.element.querySelectorAll('.splide__slide'));

        return Math.max(
            slides.findIndex((slide) => slide.querySelector('[data-shop-tabs-active="true"]')),
            0
        );
    }

    getActiveSlide() {
        const slides = Array.from(this.element.querySelectorAll('.splide__slide'));

        return slides[this.getActiveSlideIndex()] ?? null;
    }

    getSlideIndex(slide) {
        if (!slide) {
            return -1;
        }

        const slides = Array.from(this.element.querySelectorAll('.splide__slide'));

        return slides.indexOf(slide);
    }

    shouldMoveToSlide(slide) {
        if (!slide) {
            return false;
        }

        if (this.isMobile()) {
            return true;
        }

        return !this.isSlideFullyVisible(slide);
    }

    moveToSlide(slide, index) {
        if (!this.splide || index < 0) {
            return;
        }

        if (!this.isMobile()) {
            this.splide.go(index);
            return;
        }

        if (index === 0) {
            this.splide.go(0);
            return;
        }

        const destination = this.getCenteredDestination(slide);

        if (destination === null) {
            this.splide.go(index);
            return;
        }

        this.splide.Components.Controller.scroll(
            destination,
            this.splide.options.speed,
            false
        );
    }

    getCenteredDestination(slide) {
        if (!this.splide || !slide) {
            return null;
        }

        const track = this.element.querySelector('.splide__track');

        if (!track) {
            return null;
        }

        const { Move } = this.splide.Components;
        const trackRect = track.getBoundingClientRect();
        const slideRect = slide.getBoundingClientRect();
        const delta = slideRect.left + slideRect.width / 2 - (trackRect.left + trackRect.width / 2);
        const rawDestination = Move.getPosition() - delta;
        const minLimit = Math.min(Move.getLimit(false), Move.getLimit(true));
        const maxLimit = Math.max(Move.getLimit(false), Move.getLimit(true));

        return Math.min(maxLimit, Math.max(minLimit, rawDestination));
    }

    syncActiveSlidePosition() {
        if (!this.splide) {
            return;
        }

        const activeSlide = this.getSelectedSlide();

        if (!activeSlide) {
            return;
        }

        const index = this.getSlideIndex(activeSlide);

        if (index >= 0 && this.shouldMoveToSlide(activeSlide)) {
            this.moveToSlide(activeSlide, index);
        }

        this.updatePagination();
    }

    isMobile() {
        return window.matchMedia('(max-width: 767px)').matches;
    }

    isSlideFullyVisible(slide) {
        const track = this.element.querySelector('.splide__track');

        if (!track) {
            return false;
        }

        const trackRect = track.getBoundingClientRect();
        const slideRect = slide.getBoundingClientRect();
        const tolerance = 4;

        return (
            slideRect.left >= trackRect.left - tolerance &&
            slideRect.right <= trackRect.right + tolerance
        );
    }

    getSelectedSlide() {
        const slides = Array.from(this.element.querySelectorAll('.splide__slide'));

        return slides[this.selectedIndex] ?? this.getActiveSlide();
    }

    selectSlide(slide, index) {
        if (index < 0) {
            return;
        }

        this.selectedIndex = index;
        this.updatePagination();

        if (this.shouldMoveToSlide(slide)) {
            this.moveToSlide(slide, index);
        }
    }

    navigateToSlide(slide) {
        const link = slide?.querySelector('[data-shop-tabs-link]');

        if (!link) {
            return;
        }

        link.click();
    }

    renderPagination() {
        const pagination = this.element.querySelector('.splide__pagination');

        if (!pagination) {
            return;
        }

        const slides = Array.from(this.element.querySelectorAll('.splide__slide'));

        pagination.innerHTML = '';
        this.paginationButtons = slides.map((slide, index) => {
            const button = document.createElement('button');
            button.type = 'button';
            button.className = 'splide__pagination__page';
            button.setAttribute('aria-label', `Aller a la categorie ${index + 1}`);
            button.addEventListener('click', () => {
                this.selectSlide(slide, index);
                this.navigateToSlide(slide);
            });

            const item = document.createElement('li');
            item.className = 'splide__pagination__item';
            item.appendChild(button);
            pagination.appendChild(item);

            return button;
        });

        this.updatePagination();
    }

    updatePagination() {
        this.paginationButtons.forEach((button, index) => {
            const isActive = index === this.selectedIndex;

            button.classList.toggle('is-active', isActive);
            button.setAttribute('aria-current', isActive ? 'true' : 'false');
        });
    }
}
