'use client';
import { useControllableState, useEventCallback } from '@fluentui/react-utilities';
import EmblaCarousel from 'embla-carousel';
import * as React from 'react';
import { carouselCardClassNames } from './CarouselCard/useCarouselCardStyles.styles';
import { carouselSliderClassNames } from './CarouselSlider/useCarouselSliderStyles.styles';
import Autoplay from 'embla-carousel-autoplay';
import Fade from 'embla-carousel-fade';
import { pointerEventPlugin } from './pointerEvents';
const sliderClassname = `.${carouselSliderClassNames.root}`;
const DEFAULT_EMBLA_OPTIONS = {
    containScroll: 'trimSnaps',
    inViewThreshold: 0.99,
    watchDrag: false,
    skipSnaps: true,
    container: sliderClassname,
    slides: `.${carouselCardClassNames.root}`
};
export const EMBLA_VISIBILITY_EVENT = 'embla:visibilitychange';
export function setTabsterDefault(element, isDefault) {
    const tabsterAttr = element.getAttribute('data-tabster');
    if (tabsterAttr) {
        const tabsterAttributes = JSON.parse(tabsterAttr);
        if (tabsterAttributes.focusable) {
            // If tabster.focusable isn't present, we will ignore.
            tabsterAttributes.focusable.isDefault = isDefault;
            element.setAttribute('data-tabster', JSON.stringify(tabsterAttributes));
        }
    }
}
export function useEmblaCarousel(options) {
    const { align, autoplayInterval, direction, loop, slidesToScroll, watchDrag, containScroll, motion, onDragIndexChange, onAutoplayIndexChange } = options;
    var _motion_kind;
    const motionType = typeof motion === 'string' ? motion : (_motion_kind = motion === null || motion === void 0 ? void 0 : motion.kind) !== null && _motion_kind !== void 0 ? _motion_kind : 'slide';
    var _motion_duration;
    const motionDuration = typeof motion === 'string' ? 25 : (_motion_duration = motion === null || motion === void 0 ? void 0 : motion.duration) !== null && _motion_duration !== void 0 ? _motion_duration : 25;
    const [activeIndex, setActiveIndex] = useControllableState({
        defaultState: options.defaultActiveIndex,
        state: options.activeIndex,
        initialState: 0
    });
    const onDragEvent = useEventCallback((event, index)=>{
        onDragIndexChange === null || onDragIndexChange === void 0 ? void 0 : onDragIndexChange(event, {
            event,
            type: 'drag',
            index
        });
    });
    const emblaOptions = React.useRef({
        align,
        direction,
        loop,
        slidesToScroll,
        startIndex: activeIndex,
        watchDrag,
        containScroll,
        duration: motionDuration
    });
    const emblaApi = React.useRef(null);
    const autoplayRef = React.useRef(false);
    const resetAutoplay = React.useCallback(()=>{
        var _emblaApi_current_plugins_autoplay, _emblaApi_current;
        (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : (_emblaApi_current_plugins_autoplay = _emblaApi_current.plugins().autoplay) === null || _emblaApi_current_plugins_autoplay === void 0 ? void 0 : _emblaApi_current_plugins_autoplay.reset();
    }, []);
    const getPlugins = React.useCallback(()=>{
        const plugins = [];
        plugins.push(Autoplay({
            playOnInit: autoplayRef.current,
            delay: autoplayInterval,
            /* stopOnInteraction: false causes autoplay to restart on interaction end*/ /* we'll handle this logic to ensure autoplay state is respected */ stopOnInteraction: true,
            stopOnFocusIn: false,
            stopOnMouseEnter: false
        }));
        // Optionally add Fade plugin
        if (motionType === 'fade') {
            plugins.push(Fade());
        }
        if (watchDrag) {
            plugins.push(pointerEventPlugin({
                onSelectViaDrag: onDragEvent
            }));
        }
        return plugins;
    }, [
        motionType,
        onDragEvent,
        watchDrag,
        autoplayInterval
    ]);
    /* This function enables autoplay to pause/play without affecting underlying state
   * Useful for pausing on focus etc. without having to reinitialize or set autoplay to off
   */ const enableAutoplay = React.useCallback((autoplay, temporary)=>{
        if (!temporary) {
            autoplayRef.current = autoplay;
        }
        if (autoplay && autoplayRef.current) {
            var // Autoplay should only enable in the case where underlying state is true, temporary should not override
            _emblaApi_current_plugins_autoplay, _emblaApi_current;
            (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : (_emblaApi_current_plugins_autoplay = _emblaApi_current.plugins().autoplay) === null || _emblaApi_current_plugins_autoplay === void 0 ? void 0 : _emblaApi_current_plugins_autoplay.play();
            // Reset after play to ensure timing and any focus/mouse pause state is reset.
            resetAutoplay();
        } else if (!autoplay) {
            var _emblaApi_current_plugins_autoplay1, _emblaApi_current1;
            (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : (_emblaApi_current_plugins_autoplay1 = _emblaApi_current1.plugins().autoplay) === null || _emblaApi_current_plugins_autoplay1 === void 0 ? void 0 : _emblaApi_current_plugins_autoplay1.stop();
        }
    }, [
        resetAutoplay
    ]);
    // Listeners contains callbacks for UI elements that may require state update based on embla changes
    const listeners = React.useRef(new Set());
    const subscribeForValues = React.useCallback((listener)=>{
        listeners.current.add(listener);
        return ()=>{
            listeners.current.delete(listener);
        };
    }, []);
    const updateIndex = ()=>{
        var _emblaApi_current, _emblaApi_current1, _emblaApi_current2, _slideRegistry_newIndex;
        var _emblaApi_current_selectedScrollSnap;
        const newIndex = (_emblaApi_current_selectedScrollSnap = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.selectedScrollSnap()) !== null && _emblaApi_current_selectedScrollSnap !== void 0 ? _emblaApi_current_selectedScrollSnap : 0;
        const slides = (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.slideNodes();
        const slideRegistry = (_emblaApi_current2 = emblaApi.current) === null || _emblaApi_current2 === void 0 ? void 0 : _emblaApi_current2.internalEngine().slideRegistry;
        var _slideRegistry_newIndex_;
        const actualIndex = (_slideRegistry_newIndex_ = slideRegistry === null || slideRegistry === void 0 ? void 0 : (_slideRegistry_newIndex = slideRegistry[newIndex]) === null || _slideRegistry_newIndex === void 0 ? void 0 : _slideRegistry_newIndex[0]) !== null && _slideRegistry_newIndex_ !== void 0 ? _slideRegistry_newIndex_ : 0;
        // We set the first card in the current group as the default tabster index for focus capture
        slides === null || slides === void 0 ? void 0 : slides.forEach((slide, slideIndex)=>{
            setTabsterDefault(slide, slideIndex === actualIndex);
        });
        setActiveIndex(newIndex);
    };
    const handleReinit = useEventCallback(()=>{
        var _emblaApi_current, _emblaApi_current1, _emblaApi_current2, _emblaApi_current3, _emblaApi_current4;
        var _emblaApi_current_slideNodes;
        const nodes = (_emblaApi_current_slideNodes = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.slideNodes()) !== null && _emblaApi_current_slideNodes !== void 0 ? _emblaApi_current_slideNodes : [];
        var _emblaApi_current_internalEngine_slideRegistry;
        const groupIndexList = (_emblaApi_current_internalEngine_slideRegistry = (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.internalEngine().slideRegistry) !== null && _emblaApi_current_internalEngine_slideRegistry !== void 0 ? _emblaApi_current_internalEngine_slideRegistry : [];
        const navItemsCount = groupIndexList.length > 0 ? groupIndexList.length : nodes.length;
        const canLoop = (_emblaApi_current2 = emblaApi.current) === null || _emblaApi_current2 === void 0 ? void 0 : _emblaApi_current2.internalEngine().slideLooper.canLoop();
        var _emblaApi_current_selectedScrollSnap;
        const data = {
            navItemsCount,
            activeIndex: (_emblaApi_current_selectedScrollSnap = (_emblaApi_current3 = emblaApi.current) === null || _emblaApi_current3 === void 0 ? void 0 : _emblaApi_current3.selectedScrollSnap()) !== null && _emblaApi_current_selectedScrollSnap !== void 0 ? _emblaApi_current_selectedScrollSnap : 0,
            groupIndexList,
            slideNodes: nodes,
            canLoop
        };
        updateIndex();
        (_emblaApi_current4 = emblaApi.current) === null || _emblaApi_current4 === void 0 ? void 0 : _emblaApi_current4.scrollTo(activeIndex, false);
        for (const listener of listeners.current){
            listener(data);
        }
    });
    const handleIndexChange = useEventCallback((_, eventType)=>{
        var _emblaApi_current;
        var _emblaApi_current_selectedScrollSnap;
        const newIndex = (_emblaApi_current_selectedScrollSnap = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.selectedScrollSnap()) !== null && _emblaApi_current_selectedScrollSnap !== void 0 ? _emblaApi_current_selectedScrollSnap : 0;
        updateIndex();
        if (eventType === 'autoplay:select') {
            const noopEvent = new Event('autoplay');
            onAutoplayIndexChange === null || onAutoplayIndexChange === void 0 ? void 0 : onAutoplayIndexChange(noopEvent, {
                event: noopEvent,
                type: 'autoplay',
                index: newIndex
            });
        }
    });
    const viewportRef = React.useRef(null);
    const containerRef = React.useMemo(()=>{
        const handleVisibilityChange = ()=>{
            var _emblaApi_current, _emblaApi_current1;
            const cardElements = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.slideNodes();
            var _emblaApi_current_slidesInView;
            const visibleIndexes = (_emblaApi_current_slidesInView = (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.slidesInView()) !== null && _emblaApi_current_slidesInView !== void 0 ? _emblaApi_current_slidesInView : [];
            cardElements === null || cardElements === void 0 ? void 0 : cardElements.forEach((cardElement, index)=>{
                cardElement.dispatchEvent(new CustomEvent(EMBLA_VISIBILITY_EVENT, {
                    bubbles: false,
                    detail: {
                        isVisible: visibleIndexes.includes(index)
                    }
                }));
            });
        };
        // Get plugins using autoplayRef to prevent state change recreating EmblaCarousel
        const plugins = getPlugins();
        return {
            set current (newElement){
                if (emblaApi.current) {
                    var // Stop autoplay before reinitializing.
                    _emblaApi_current_plugins_autoplay, _emblaApi_current_plugins, _emblaApi_current;
                    (_emblaApi_current_plugins = (_emblaApi_current = emblaApi.current).plugins) === null || _emblaApi_current_plugins === void 0 ? void 0 : (_emblaApi_current_plugins_autoplay = _emblaApi_current_plugins.call(_emblaApi_current).autoplay) === null || _emblaApi_current_plugins_autoplay === void 0 ? void 0 : _emblaApi_current_plugins_autoplay.stop();
                    emblaApi.current.off('slidesInView', handleVisibilityChange);
                    emblaApi.current.off('select', handleIndexChange);
                    emblaApi.current.off('reInit', handleReinit);
                    emblaApi.current.off('autoplay:select', handleIndexChange);
                    emblaApi.current.destroy();
                    emblaApi.current = null;
                }
                if (newElement) {
                    var // Use direct viewport if available, else fallback to container (includes Carousel controls).
                    _viewportRef_current;
                    const newEmblaApi = EmblaCarousel((_viewportRef_current = viewportRef.current) !== null && _viewportRef_current !== void 0 ? _viewportRef_current : newElement, {
                        ...DEFAULT_EMBLA_OPTIONS,
                        ...emblaOptions.current
                    }, plugins);
                    newEmblaApi.on('reInit', handleReinit);
                    newEmblaApi.on('slidesInView', handleVisibilityChange);
                    newEmblaApi.on('select', handleIndexChange);
                    newEmblaApi.on('autoplay:select', handleIndexChange);
                    emblaApi.current = newEmblaApi;
                }
            }
        };
    }, [
        getPlugins,
        handleIndexChange,
        handleReinit
    ]);
    const carouselApi = React.useMemo(()=>({
            scrollToElement: (element, jump)=>{
                var _emblaApi_current, _emblaApi_current1, _emblaApi_current2;
                const cardElements = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.slideNodes();
                var _emblaApi_current_internalEngine_slideRegistry;
                const groupIndexList = (_emblaApi_current_internalEngine_slideRegistry = (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.internalEngine().slideRegistry) !== null && _emblaApi_current_internalEngine_slideRegistry !== void 0 ? _emblaApi_current_internalEngine_slideRegistry : [];
                var _cardElements_indexOf;
                const cardIndex = (_cardElements_indexOf = cardElements === null || cardElements === void 0 ? void 0 : cardElements.indexOf(element)) !== null && _cardElements_indexOf !== void 0 ? _cardElements_indexOf : 0;
                const groupIndex = groupIndexList.findIndex((group)=>{
                    return group.includes(cardIndex);
                });
                const indexFocus = groupIndex !== null && groupIndex !== void 0 ? groupIndex : cardIndex;
                (_emblaApi_current2 = emblaApi.current) === null || _emblaApi_current2 === void 0 ? void 0 : _emblaApi_current2.scrollTo(indexFocus, jump);
                return indexFocus;
            },
            scrollToIndex: (index, jump)=>{
                var _emblaApi_current;
                (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.scrollTo(index, jump);
            },
            scrollInDirection: (dir)=>{
                var _emblaApi_current;
                if (dir === 'prev') {
                    var _emblaApi_current1;
                    (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.scrollPrev();
                } else {
                    var _emblaApi_current2;
                    (_emblaApi_current2 = emblaApi.current) === null || _emblaApi_current2 === void 0 ? void 0 : _emblaApi_current2.scrollNext();
                }
                var _emblaApi_current_selectedScrollSnap;
                return (_emblaApi_current_selectedScrollSnap = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.selectedScrollSnap()) !== null && _emblaApi_current_selectedScrollSnap !== void 0 ? _emblaApi_current_selectedScrollSnap : 0;
            }
        }), []);
    React.useEffect(()=>{
        var // Stop autoplay before reinitializing.
        _emblaApi_current_plugins_autoplay, _emblaApi_current_plugins, _emblaApi_current, _emblaApi_current1;
        const plugins = getPlugins();
        emblaOptions.current = {
            startIndex: emblaOptions.current.startIndex,
            align,
            direction,
            loop,
            slidesToScroll,
            watchDrag,
            containScroll,
            duration: motionDuration
        };
        (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : (_emblaApi_current_plugins = _emblaApi_current.plugins) === null || _emblaApi_current_plugins === void 0 ? void 0 : (_emblaApi_current_plugins_autoplay = _emblaApi_current_plugins.call(_emblaApi_current).autoplay) === null || _emblaApi_current_plugins_autoplay === void 0 ? void 0 : _emblaApi_current_plugins_autoplay.stop();
        (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.reInit({
            ...DEFAULT_EMBLA_OPTIONS,
            ...emblaOptions.current
        }, plugins);
    }, [
        align,
        containScroll,
        direction,
        getPlugins,
        loop,
        slidesToScroll,
        watchDrag,
        motionDuration
    ]);
    React.useEffect(()=>{
        var _emblaApi_current, _emblaApi_current_slideNodes, _emblaApi_current1;
        var _emblaApi_current_selectedScrollSnap;
        // Scroll to controlled values on update
        // If active index is out of bounds, re-init will handle instead
        const currentActiveIndex = (_emblaApi_current_selectedScrollSnap = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.selectedScrollSnap()) !== null && _emblaApi_current_selectedScrollSnap !== void 0 ? _emblaApi_current_selectedScrollSnap : 0;
        var _emblaApi_current_slideNodes_length;
        const slideLength = (_emblaApi_current_slideNodes_length = (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : (_emblaApi_current_slideNodes = _emblaApi_current1.slideNodes()) === null || _emblaApi_current_slideNodes === void 0 ? void 0 : _emblaApi_current_slideNodes.length) !== null && _emblaApi_current_slideNodes_length !== void 0 ? _emblaApi_current_slideNodes_length : 0;
        emblaOptions.current.startIndex = activeIndex;
        if (activeIndex < slideLength && activeIndex !== currentActiveIndex) {
            var _emblaApi_current2;
            (_emblaApi_current2 = emblaApi.current) === null || _emblaApi_current2 === void 0 ? void 0 : _emblaApi_current2.scrollTo(activeIndex);
        }
    }, [
        activeIndex
    ]);
    return {
        activeIndex,
        carouselApi,
        viewportRef,
        containerRef,
        subscribeForValues,
        enableAutoplay,
        resetAutoplay
    };
}
