(function ($, elementor) {
    "use strict";

    const Gigneo_Widgets = {

        init: function () {
            const widgets = {
                'gigneo-search-bar.default': Gigneo_Widgets.Search_Bar,
                'gigneo-repeater.default': Gigneo_Widgets.Repeater,
                'gigneo-freelancer-archive.default': Gigneo_Widgets.Freelancer_Archive,
                'gigneo-service-archive.default': Gigneo_Widgets.Service_Archive,
                'gigneo-employer-archive.default': Gigneo_Widgets.Employer_Archive,
                'gigneo-job-archive.default': Gigneo_Widgets.Job_Archive,
                'gigneo-service-info.default': Gigneo_Widgets.Service_Info,
                'gigneo-horizontal-menu.default': Gigneo_Widgets.Horizontal_Menu,
                'gigneo-service-grid.default': Gigneo_Widgets.Service_Grid,
                'gigneo-service-carousel.default': Gigneo_Widgets.Service_Carousel,
                'gigneo-freelancer-carousel.default': Gigneo_Widgets.Freelancer_Carousel,
                'gigneo-employer-carousel.default': Gigneo_Widgets.Employer_Carousel,
                'gigneo-job-carousel.default': Gigneo_Widgets.Job_Carousel,
                'gigneo-job-grid.default': Gigneo_Widgets.Job_Grid,
            };

            $.each(widgets, function (widgetName, callback) {
                elementorFrontend.hooks.addAction('frontend/element_ready/' + widgetName, callback);
            });
        },

        Search_Bar: function (scope) {
            const settings = Gigneo_Widgets.getElementSettings(scope);
            const selector = scope.find('.gn-ele-search-bar-wrapper .gn-search-bar-form');

            if (!selector.length) {
                return;
            }

            window.GigneoSelect2.init();

            $(selector).on('submit', function (e) {
                e.preventDefault();

                let urls = selector.data('gn-urls');
                let type = selector.find('[name="type"]').val();
                let search = selector.find('[name="search"]').val();
                let url = urls[type] ?? false;

                if (url) {
                    window.location.href = url + '?search=' + search;
                }

            });
        },

        Repeater: function (scope) {
            const settings = Gigneo_Widgets.getElementSettings(scope);
            const selector = scope.find('.gn-repeater-layout-carousel');

            if (!selector.length) {
                return;
            }

            let config = Gigneo_Widgets.swiperConfig(settings, scope);

            Gigneo_Widgets.swiperInit(selector, config);
        },

        Freelancer_Archive: function (scope) {
            const settings = Gigneo_Widgets.getElementSettings(scope);
            const selector = scope.find('.gn-freelancer-archive-wrapper');

            if (!selector.length) {
                return;
            }

            window.GigneoSelect2.init();
        },

        Service_Archive: function (scope) {
            const settings = Gigneo_Widgets.getElementSettings(scope);
            const selector = scope.find('.gn-service-archive-wrapper');

            if (!selector.length) {
                return;
            }

            window.GigneoSelect2.init();
        },

        Employer_Archive: function (scope) {
            const settings = Gigneo_Widgets.getElementSettings(scope);
            const selector = scope.find('.gn-employer-archive-wrapper');

            if (!selector.length) {
                return;
            }

            window.GigneoSelect2.init();
        },

        Job_Archive: function (scope) {
            const settings = Gigneo_Widgets.getElementSettings(scope);
            const selector = scope.find('.gn-job-archive-wrapper');

            if (!selector.length) {
                return;
            }

            window.GigneoSelect2.init();
        },

        Service_Grid: function (scope) {
            const filterList = scope.find('.gn-services-grid-filter-list');
            const $grid = scope.find('.gn-ele-service-grid-wrapper');

            if (!$grid.length) {
                return;
            }

            // Only initialize Isotope logic when category filter list is enabled
            if (filterList.length && typeof $.fn.isotope !== 'undefined') {
                $grid.addClass('gn-active');
                const iso = $grid.isotope({
                    itemSelector: '.gn-service-card-item',
                    layoutMode: 'fitRows',
                    percentPosition: true,
                    transitionDuration: '0.4s'
                });

                if (typeof $.fn.imagesLoaded !== 'undefined') {
                    $grid.imagesLoaded().progress(function () {
                        iso.isotope('layout');
                    });
                }

                filterList.on('click', '.gn-services-grid-filter-item', function (e) {
                    e.preventDefault();
                    const $this = $(this);
                    const filterValue = $this.attr('data-filter');

                    $this.siblings().removeClass('active');
                    $this.addClass('active');

                    if (iso && typeof iso.isotope === 'function') {
                        iso.isotope({filter: filterValue});
                    }
                });

            }

            // Media slider
            const $sliders = scope.find('.gn-service-media-slider');
            if ($sliders.length && typeof $.fn.slick !== 'undefined') {
                $sliders.each(function () {
                    const $slider = $(this);
                    if (!$slider.hasClass('slick-initialized')) {
                        $slider.slick({
                            dots: true,
                            arrows: true,
                            infinite: false,
                            speed: 300,
                            slidesToShow: 1,
                            slidesToScroll: 1,
                            rtl: $('html').attr('dir') === 'rtl'
                        });
                    }
                });
            }
        },

        Freelancer_Carousel: function (scope) {
            const settings = Gigneo_Widgets.getElementSettings(scope);
            const selector = scope.find('.gn-ele-freelancer-carousel');

            if (!selector.length) {
                return;
            }

            let config = Gigneo_Widgets.swiperConfig(settings, scope);

            Gigneo_Widgets.swiperInit(selector, config);
        },

        Employer_Carousel: function (scope) {
            const settings = Gigneo_Widgets.getElementSettings(scope);
            const selector = scope.find('.gn-ele-employer-carousel');

            if (!selector.length) {
                return;
            }

            let config = Gigneo_Widgets.swiperConfig(settings, scope);

            Gigneo_Widgets.swiperInit(selector, config);
        },

        Job_Carousel: function (scope) {
            const settings = Gigneo_Widgets.getElementSettings(scope);
            const selector = scope.find('.gn-ele-job-carousel');

            if (!selector.length) {
                return;
            }

            let config = Gigneo_Widgets.swiperConfig(settings, scope);

            Gigneo_Widgets.swiperInit(selector, config);
        },

        Service_Carousel: function (scope) {
            const settings = Gigneo_Widgets.getElementSettings(scope);
            const selector = scope.find('.gn-ele-service-carousel');

            if (!selector.length) {
                return;
            }

            let config = Gigneo_Widgets.swiperConfig(settings, scope);

            Gigneo_Widgets.swiperInit(selector, config);

            // Media slider inside cards
            const $sliders = scope.find('.gn-service-media-slider');
            if ($sliders.length && typeof $.fn.slick !== 'undefined') {
                $sliders.each(function () {
                    const $slider = $(this);
                    if (!$slider.hasClass('slick-initialized')) {
                        $slider.slick({
                            dots: true,
                            arrows: true,
                            infinite: false,
                            speed: 300,
                            slidesToShow: 1,
                            slidesToScroll: 1,
                            rtl: $('html').attr('dir') === 'rtl'
                        });
                    }
                });
            }
        },

        Job_Grid: function (scope) {
            const filterList = scope.find('.gn-jobs-grid-filter-list');
            const $grid = scope.find('.gn-ele-job-grid-wrapper');

            if (!$grid.length) {
                return;
            }

            // Only initialize Isotope logic when category filter list is enabled
            if (filterList.length && typeof $.fn.isotope !== 'undefined') {
                $grid.addClass('gn-active');
                const iso = $grid.isotope({
                    itemSelector: '.gn-job-card-item',
                    layoutMode: 'fitRows',
                    percentPosition: true,
                    transitionDuration: '0.4s'
                });

                if (typeof $.fn.imagesLoaded !== 'undefined') {
                    $grid.imagesLoaded().progress(function () {
                        iso.isotope('layout');
                    });
                }

                filterList.on('click', '.gn-jobs-grid-filter-item', function (e) {
                    e.preventDefault();
                    const $this = $(this);
                    const filterValue = $this.attr('data-filter');

                    $this.siblings().removeClass('active');
                    $this.addClass('active');

                    if (iso && typeof iso.isotope === 'function') {
                        iso.isotope({filter: filterValue});
                    }
                });
            }
        },

        Service_Info: function (scope) {
            const settings = Gigneo_Widgets.getElementSettings(scope);
            const selector = scope.find('.gn-service-media-slider');

            if (!selector.length) {
                return;
            }

            //Media slider
            selector.slick({
                dots: true,
                arrows: true,
                infinite: false,
                speed: 300,
                slidesToShow: 1,
                slidesToScroll: 1,
                rtl: $('html').attr('dir') === 'rtl'

            });
        },

        Horizontal_Menu: function (scope) {
            const selector = scope.find('.gn-ele-horizontal-menu-wrapper');

            if (!selector.length) {
                return false;
            }

            // Responsive toggle
            selector.find('.gn-horizontal-responsive-menu-toggle')
                .off('click.gnMenu')
                .on('click.gnMenu', function (e) {
                    e.preventDefault();
                    selector.toggleClass('gn-responsive-active');
                });

            // Mobile submenu toggle
            selector.find('.gn-submenu-icon')
                .off('click.gnMenu')
                .on('click.gnMenu', function (e) {
                    e.preventDefault();
                    e.stopPropagation();

                    $(this)
                        .closest('.menu-item-has-children')
                        .toggleClass('gn-active');
                });

            // Hover + Edge Detection
            selector.find('li.menu-item-has-children')
                .off('mouseenter.gnMenu')
                .on('mouseenter.gnMenu', function () {

                    const submenu = $(this).children('.sub-menu');

                    if (!submenu.length) return;

                    // Reset previous edge class
                    submenu.removeClass('gn-submenu-edge');

                    // Don't flip if parent is already flipped
                    const parentSubmenu = $(this).closest('.sub-menu');
                    if (parentSubmenu.hasClass('gn-submenu-edge')) {
                        return;
                    }

                    const rect = submenu[0].getBoundingClientRect();

                    if (rect.right > window.innerWidth) {
                        submenu.addClass('gn-submenu-edge');
                    }
                });

            // Initial edge check for all submenus (runs once on init)
            function checkAllSubmenuEdges() {
                selector.find('ul.sub-menu').each(function () {
                    const submenu = $(this);
                    const rect = submenu[0].getBoundingClientRect();

                    submenu.removeClass('gn-submenu-edge');

                    if (rect.right > window.innerWidth) {
                        submenu.addClass('gn-submenu-edge');
                    }
                });
            }

            // Run initial check
            checkAllSubmenuEdges();

            // Re-check on window resize (important for responsive behavior)
            $(window).off('resize.gnMenu').on('resize.gnMenu', function () {
                checkAllSubmenuEdges();
            });
        },

        //Get Element Settings
        getElementSettings: function (element, key = null) {
            let elementSettings = {};
            const modelCID = element.data('model-cid');

            if (elementorFrontend.isEditMode() && modelCID) {
                const settingsModel = elementorFrontend.config.elements.data[modelCID];
                const type = settingsModel.attributes.widgetType || settingsModel.attributes.elType;
                let settingsKeys = elementorFrontend.config.elements.keys[type];
                const devices = elementorFrontend.breakpoints.getActiveBreakpointsList({
                    withDesktop: false,
                }) || ['tablet', 'mobile'];

                if (!settingsKeys) {
                    settingsKeys = elementorFrontend.config.elements.keys[type] = [];
                    $.each(settingsModel.controls, (controlName, control) => {
                        if (control.frontend_available) {
                            settingsKeys.push(controlName);
                        }
                    });
                }

                $.each(settingsModel.getActiveControls(), (controlKey) => {
                    if (!settingsKeys.includes(controlKey)) {
                        return;
                    }

                    elementSettings[controlKey] = settingsModel.attributes[controlKey];

                    // Include responsive device variants (e.g. slides_to_show_tablet).
                    $.each(devices, function (_, device) {
                        const deviceKey = controlKey + '_' + device;
                        if (settingsModel.attributes[deviceKey] !== undefined) {
                            elementSettings[deviceKey] = settingsModel.attributes[deviceKey];
                        }
                    });
                });
            } else {
                elementSettings = element.data('settings') || {};
            }

            return key ? Gigneo_Widgets.getItems(elementSettings, key) : elementSettings;
        },

        getItems: function (items, keyPath) {
            if (!keyPath) {
                return items;
            }

            const keys = keyPath.split('.');
            let value = items;

            for (let i = 0; i < keys.length; i++) {
                if (value == null) {
                    return undefined;
                }
                value = value[keys[i]];
            }

            return value;
        },

        getResponsiveSetting: function (settings, key, device, fallback) {
            if (device) {
                const deviceValue = settings[key + '_' + device];
                if (deviceValue !== undefined && deviceValue !== null && deviceValue !== '') {
                    return deviceValue;
                }
                return fallback;
            }

            const baseValue = settings[key];
            if (baseValue !== undefined && baseValue !== null && baseValue !== '') {
                return baseValue;
            }

            return fallback;
        },

        // Build Swiper config from Elementor settings
        swiperConfig: function (settings = {}, scope, overrides = {}) {
            const slidesToShow = parseFloat(settings.slides_to_show) || 1;
            const slidesToScroll = parseInt(settings.slides_to_scroll || 1, 10);
            const spaceBetween = parseInt(settings.slide_space_between || settings.slides_space_between || 0, 10);
            const direction = settings.direction || 'horizontal';
            const useCustomWidth = settings.custom_slide_width === 'yes';

            let config = {
                slidesPerView: useCustomWidth ? 'auto' : slidesToShow,
                slidesPerGroup: slidesToScroll,
                spaceBetween: spaceBetween,
                speed: parseInt(settings.slides_speed || settings.speed || 600, 10),
                loop: settings.loop === 'yes',
                rewind: settings.loop !== 'yes' && settings.rewind === 'yes',
                direction: direction,
                centeredSlides: settings.centered_slides === 'yes',
                grabCursor: settings.grab_cursor === 'yes',
                allowTouchMove: settings.mouse_drag === 'yes',
                watchOverflow: true,
                observer: true,
                observeParents: true,
                observeSlideChildren: true,
                handleElementorBreakpoints: true,
            };

            // Elementor stores breakpoints as max-width; Swiper 5+ uses min-width.
            // handleElementorBreakpoints + Elementor's Swiper util remaps them correctly.
            const elementorBreakpoints = elementorFrontend.config.responsive.activeBreakpoints || {};
            const defaultSlidesToShowMap = {
                mobile: 1,
                tablet: slidesToShow > 1 ? Math.min(2, slidesToShow) : 1,
            };

            config.breakpoints = {};
            let lastBreakpointSlidesToShow = slidesToShow;
            let lastBreakpointSlidesToScroll = slidesToScroll;
            let lastBreakpointSpaceBetween = spaceBetween;

            // Walk largest → smallest (same order Elementor uses).
            Object.keys(elementorBreakpoints).reverse().forEach(function (breakpointName) {
                const defaultSlides = defaultSlidesToShowMap[breakpointName]
                    ? defaultSlidesToShowMap[breakpointName]
                    : lastBreakpointSlidesToShow;

                const bpSlidesToShow = parseFloat(
                    Gigneo_Widgets.getResponsiveSetting(
                        settings,
                        'slides_to_show',
                        breakpointName,
                        defaultSlides
                    )
                ) || defaultSlides;

                const bpSlidesToScroll = parseInt(
                    Gigneo_Widgets.getResponsiveSetting(
                        settings,
                        'slides_to_scroll',
                        breakpointName,
                        lastBreakpointSlidesToScroll
                    ),
                    10
                ) || 1;

                const bpSpaceBetween = parseInt(
                    Gigneo_Widgets.getResponsiveSetting(
                        settings,
                        'slide_space_between',
                        breakpointName,
                        Gigneo_Widgets.getResponsiveSetting(
                            settings,
                            'slides_space_between',
                            breakpointName,
                            lastBreakpointSpaceBetween
                        )
                    ),
                    10
                );

                config.breakpoints[elementorBreakpoints[breakpointName].value] = {
                    slidesPerView: useCustomWidth ? 'auto' : bpSlidesToShow,
                    slidesPerGroup: bpSlidesToScroll,
                    spaceBetween: isNaN(bpSpaceBetween) ? lastBreakpointSpaceBetween : bpSpaceBetween,
                };

                lastBreakpointSlidesToShow = bpSlidesToShow;
                lastBreakpointSlidesToScroll = bpSlidesToScroll;
                lastBreakpointSpaceBetween = isNaN(bpSpaceBetween) ? lastBreakpointSpaceBetween : bpSpaceBetween;
            });

            // Free mode
            if (settings.free_mode === 'yes') {
                config.freeMode = {
                    enabled: true,
                    sticky: false,
                };
            }

            // Keyboard
            if (settings.keyboard === 'yes') {
                config.keyboard = {
                    enabled: true,
                    onlyInViewport: true,
                };
            }

            // Mousewheel
            if (settings.mousewheel === 'yes') {
                config.mousewheel = {
                    enabled: true,
                    forceToAxis: true,
                };
            }

            // Autoplay
            if (settings.autoplay === 'yes') {
                config.autoplay = {
                    delay: parseInt(settings.autoplay_speed || 3000, 10),
                    disableOnInteraction: settings.pause_on_interaction === 'yes',
                    pauseOnMouseEnter: settings.pause_on_hover === 'yes',
                    reverseDirection: settings.reverse_direction === 'yes',
                };
            }

            // Navigation Arrows
            if (settings.arrows === 'yes') {
                const prevEl = scope && scope.length
                    ? scope.find('.gn-swiper-arrow-prev')[0]
                    : '.gn-swiper-arrow-prev';
                const nextEl = scope && scope.length
                    ? scope.find('.gn-swiper-arrow-next')[0]
                    : '.gn-swiper-arrow-next';

                config.navigation = {
                    enabled: true,
                    prevEl: prevEl,
                    nextEl: nextEl,
                };
            }

            // Pagination
            if (settings.bullets === 'yes') {
                const paginationEl = scope && scope.length
                    ? scope.find('.gn-swiper-bullets')[0]
                    : '.gn-swiper-bullets';

                config.pagination = {
                    el: paginationEl,
                    clickable: true,
                };
            }

            return $.extend(true, config, overrides);
        },

        //Swiper Initialization
        swiperInit: function (selector, config) {
            const $el = selector instanceof jQuery ? selector : $(selector);

            if (!$el.length) {
                return;
            }

            // Destroy any previous instance on this element.
            if ($el[0].swiper) {
                $el[0].swiper.destroy(true, true);
            }

            // Always use Elementor's Swiper util so handleElementorBreakpoints is applied.
            const asyncSwiper = elementorFrontend.utils.swiper;

            new asyncSwiper($el, config).then(function (instance) {
                $el[0].swiper = instance;
            });
        },
    };

    // Initialize when Elementor frontend is ready
    $(window).on('elementor/frontend/init', Gigneo_Widgets.init);

})(jQuery, window.elementorFrontend);