import type { LngLat } from '@yandex/ymaps3-types';
import type { Feature } from '@yandex/ymaps3-clusterer';
//import { BOUNDS, LOCATION } from './common';

window.map = null;
window.swiperDinamic = null;

function searchScreens(q = '', filter = {}, sort = 'sort') {

    if (window.detail && !window.showAll) {
        filter.ID = window.detail;
    }


    if (window.detail && window.showAll && window.detailCity) {
        filter.CITY = window.detailCity;
    }





    $.ajax({
        url: '/ajax/get-coords.php', // The URL to the API endpoint
        type: 'GET', // The HTTP method to use for the request
        dataType: 'json', // The type of data expected back from the server
        data: {
            q: q,
            filter: filter,
            sort: sort
        },
        success: function (response) {
            var pointsList = [];
            // Code to execute when the request is successful
            //console.log('Data retrieved:', response);


            let list = Object.values(response.sorted);
            // console.log(response);
            list.forEach(element => {
                pointsList.push({
                    'type': 'Feature',
                    'id': element.id,
                    'degress': element.degress,
                    'popup': element.popup,
                    'double': element.double,
                    'geometry': {
                        'type': 'Point',
                        'coordinates': [element.coords.ln, element.coords.lt]
                    }
                });
            });

            let jsonStyle = response.style;

            /*const source = $("#item-template").html();
            const template = Handlebars.compile(source);
            const html = template({ items: response.list });
            $('.map-overlay--list').html(html);*/

            $('.map-overlay--list').html('');

            list.forEach(element => {
                $('.map-overlay--list').append(element.popup);
            })

            $('.map-overlay--counter').text(response.count);

            if (window.swiperDinamic) {
                window.swiperDinamic.destroy();
            }


            if ((!window.detail || window.showAll)) {
                $('.swiper-dinamic').show();
            } else {
                $('.swiper-dinamic').hide();
            }

            let $swiperWrapper = $('.swiper-dinamic').find('.swiper-wrapper');
            $swiperWrapper.html('');
            list.forEach(element => {
                let $slide = $('<div class="swiper-slide" style="width: 20rem;" data-id="' + element.id + '"></div>');
                $slide.attr('data-coords', JSON.stringify(element.coords));
                $slide.append(element.popup);
                $swiperWrapper.append($slide);
            });


            window.swiperDinamic = new Swiper('.swiper-dinamic', {
                slidesPerView: 'auto',
                spaceBetween: 14,
                on: {
                    slideChangeTransitionEnd: function (swiper) {
                        let activeSlide = swiper.slides[swiper.activeIndex];
                        // Retrieve the coordinates data from the active slide
                        let coords = JSON.parse($(activeSlide).attr('data-coords'));
                        // Console log the coordinates
                        //console.log(coords);


                        // Update the center of the map to the new coordinates
                        let baseCenter = [coords.ln, coords.lt];

                        let locationData = {
                            center: baseCenter,
                            zoom: 18,
                            duration: 500
                        };
                        if (window.NotNeedZoom) {
                            locationData = {
                                center: baseCenter,
                                duration: 500
                            };
                        }

                        window.map.update(
                            {
                                location: locationData,
                            }
                        );




                        window.NotNeedZoom = false;

                    }
                }

            });




            main(pointsList, jsonStyle);

        },
        error: function (xhr, status, error) {
            // Code to execute in case of an error
            console.log('Error:', error);
        }
    });
}


function getFilterTags() {
    const filterTags = [];
    const values = [];
    $('.filter-selected-tags').hide();
    $('.js-select-filter').each(function () {
        const select = $(this);
        const code = select.attr('name');
        const options = select.find('option:selected');


        options.each(function () {
            const option = $(this);
            if (option.val()) {
                values.push({
                    code: code,
                    name: option.text().trim(),
                    value: option.val()
                });
                $('.filter-selected-tags').css('display', 'flex');
            }
        });

        /*if (values.length > 0) {
            filterTags.push({
                code: code,
                values: values
            });
        }*/
    });

    return values;
}


// Функция для обновления блока
function updateMapFilter(filter) {
    $.ajax({
        url: window.location.href, // Используем текущий URL
        method: 'GET',
        data: {
            filter: filter
        },
        success: function (data) {
            // Создаем временный элемент для парсинга полученного HTML
            var tempDiv = $('<div>').html(data);

            // Находим новый содержимый блок .map-filter в полученных данных
            var newContent = tempDiv.find('.map-filter').html();

            // Обновляем содержимое блока .map-filter
            $('.map-filter').html(newContent);

            setTimeout(() => {
                initSelect();
            }, 10);
        },
        error: function (jqXHR, textStatus, errorThrown) {
            console.error('Ошибка при загрузке данных: ' + textStatus, errorThrown);
        }
    });
}

function searchInit() {
    let filter = {};
    let valueCounter = 0;

    $('.js-select-filter').each(function () {
        let localValues = $(this).val();
        valueCounter += localValues.length;
        filter[$(this).attr('name')] = $(this).val();
    });

    //console.log(valueCounter);


    const filterTags = getFilterTags();
    //console.log(filterTags);

    // Компиляция шаблона Handlebars
    const source = document.getElementById("filter-tag-template").innerHTML;
    const template = Handlebars.compile(source);
    // Генерация HTML
    const filterTagsHtml = template({ filterTags: filterTags });

    $('.filter-selected-tags').html(filterTagsHtml);

    //console.log(filter);


    let q = $('.js-search').val();

    if (window.map) {
        //window.map.removeChild(window.clusterer);
        //window.clusterer = null;
        //! window.map.destroy();

    }
    let sort = $('#js-sort-item').val();

    searchScreens(q, filter, sort);

    updateMapFilter(filter);

}


$(document).on('change', '.js-select-filter', function () {
    //!searchInit();
});
//js-show-single
$(document).on('click', '.js-show-single', function () {
    window.showAll = false;
    searchInit();
});
//js-show-all
$(document).on('click', '.js-show-all', function () {
    window.showAll = true;
    searchInit();
});

$(document).on('input', '.js-search', function () {
    // searchInit();
    clearTimeout(window.timer);
    window.timer = setTimeout(function () {
        searchInit();
    }, 800);
});



searchScreens();
initSelect();

function deactivateSelectOption(code, value) {
    const select = $('.js-select-filter[name=' + code + ']');
    const optionToDeactivate = select.find('option[value="' + value + '"]');

    if (optionToDeactivate.length > 0) {
        optionToDeactivate.prop('selected', false);
        select.trigger('change');
        //console.log(select.val());
    }
}
//filter-tag
$(document).on('click', '.filter-tag-remove-btn', function (e) {

    let code = $(this).data('code');
    let value = $(this).data('value');
    deactivateSelectOption(code, value);
    let $parent = $(this).closest('.filter-tag');
    $parent.remove();

    let filter = {};
    let valueCounter = 0;

    $('.js-select-filter').each(function () {
        let localValues = $(this).val();
        valueCounter += localValues.length;
        filter[$(this).attr('name')] = $(this).val();
    });

    //console.log(valueCounter);
    if (valueCounter <= 0) {
        $('.filter-selected-tags').hide();
    }


    clearTimeout(window.timer);
    window.timer = setTimeout(function () {
        searchInit();
    }, 300);

    //initSelect();
    //$('.js-select-filter[name='+code+']').val(value).trigger('change');
})

function initSelect() {


    $('select').each(function () {
        const _this = $(this),
            selectOption = _this.find('option'),
            selectOptionLength = selectOption.length,
            selectedOption = selectOption.filter(':selected'),
            duration = 150; // длительность анимации 


        _this.hide();


        const selectHead = _this.next('.new-select');


        const selectList = selectHead.next('.new-select__list');


        const selectItem = selectList.find('.new-select__item');
        let clearBtn = selectList.find('.new-select__list--clear');
        let allBtn = selectList.find('.new-select__list--all');
        //selectList.slideUp(0);
        selectList.removeClass('active');
        //selectHead.attr('data-counter', '');
        var intervalClosed;
        let w = $(window).width();
        let eventtrigger = window.matchMedia('(pointer: fine)').matches ? 'mouseenter' : 'click';

        selectHead.on(eventtrigger, function (e) {
            clearInterval(intervalClosed);





            if (!$(this).hasClass('on') || true) {

                $(this).addClass('on');
                if (_this.prop('multiple')) {
                    $('.bg-filter').addClass('active');
                    let w = $(window).width();
                    if (w <= 991) {
                        $('body').addClass('no-scroll');
                    }

                }
                //selectList.slideDown(duration);
                selectList.addClass('active');
                $('.new-select__list').not(selectList).removeClass('active');
                $('.new-select').not(selectHead).removeClass('on');
                selectItem.unbind('click');
                selectItem.on('click', function () {
                    let chooseItem = $(this).data('value');
                    let qid = _this.data('id');
                    //_this.val(chooseItem).attr('selected', 'selected');    
                    let status = $(this).hasClass('active');
                    //!selectHead.attr('data-counter', '');
                    //console.log(status);

                    if (status) {



                        if (_this.prop('multiple')) {

                            let currentValues = _this.val() || [];
                            let newValues = currentValues.filter(item => item.toString() !== chooseItem.toString());

                            _this.val(newValues);
                        } else {
                            _this.val('').removeAttr('selected');
                        }
                    } else {
                        if (_this.prop('multiple')) {
                            let currentValues = _this.val() || [];
                            if (!currentValues.includes(chooseItem)) {
                                let newValues = currentValues.concat(chooseItem);
                                _this.val(newValues);
                            }
                        } else {
                            _this.val(chooseItem).attr('selected', 'selected');
                            //!selectHead.attr('data-counter', '+1');
                        }
                    }
                    let nameSelect = _this.attr('name');
                    selectHead.text($(this).find('span').text());
                    selectList.removeClass('active');
                    selectHead.removeClass('on');

                    $('.bg-filter').removeClass('active');
                    $('body').removeClass('no-scroll');
                    $(this).toggleClass('active');
                    searchInit();
                    //console.log('click');

                    //foreach values
                    if (_this.prop('multiple')) {
                        let newText = '';
                        let textArray = [];
                        let counter = 0;
                        _this.val().forEach(function (id, index) {
                            selectOption.each(function () {
                                if ($(this).val().toString() === id.toString()) {
                                    textArray.push($(this).text());
                                    counter++;
                                }
                            })
                        });

                        newText = textArray.join(', ');
                        if (newText) {
                            selectHead.text(newText);
                        } else {
                            //selectHead.text(_this.data('placeholder'));
                        }
                        clearBtn.hide();
                        if (counter > 0) {
                            clearBtn.show();
                            selectHead.attr('data-counter', '+' + counter);
                        } else {
                            //selectHead.attr('data-counter', '');
                            let clearText = '<span class="disabled-select-value">' + _this.children('option:disabled').text() + '</span>';
                            selectHead.html(clearText);
                        }

                    }


                });

            } else {
                $(this).removeClass('on');
                $('body').removeClass('no-scroll');
                selectList.removeClass('active');
            }
        });



        selectHead.on('mouseleave', function () {
            clearInterval(intervalClosed);
            intervalClosed = setTimeout(function () {
                selectList.removeClass('active');
                selectHead.removeClass('on');
            }, 100);
        });

        selectList.on('mouseenter', function () {
            clearInterval(intervalClosed);
        });

        selectList.on('mouseleave', function () {
            clearInterval(intervalClosed);
            intervalClosed = setTimeout(function () {
                selectList.removeClass('active');
                selectHead.removeClass('on');
            }, 100);
        });

        clearBtn.on('click', function () {
            clearBtn.hide();
            let clearText = '<span class="disabled-select-value">' + _this.children('option:disabled').text() + '</span>';
            selectHead.html(clearText);
            //!selectHead.attr('data-counter', '');
            _this.val('');
            selectList.removeClass('active');
            selectHead.removeClass('on');
            const selectItem = selectList.find('.new-select__item');
            selectItem.removeClass('active');
            $('.bg-filter').removeClass('active');
            $('body').removeClass('no-scroll');
            searchInit();
        });

        allBtn.on('click', function () {


            //let clearText = '<span class="disabled-select-value">Все</span>';
            //selectHead.html(clearText);
            //! selectHead.attr('data-counter', '');
            //_this.val('');

            // Получаем все значения опций в массив
            var allOptionValues = _this.find('option').map(function () {
                return this.value;
            }).get();

            // Устанавливаем все значения для select, чтобы отметить все опции
            _this.val(allOptionValues);

            // Генерируем событие change, чтобы уведомить о новом состоянии select
            _this.trigger('change');

            selectList.removeClass('active');
            selectHead.removeClass('on');
            const selectItem = selectList.find('.new-select__item');
            selectItem.addClass('active');
            $('.bg-filter').removeClass('active');
            $('body').removeClass('no-scroll');


            let newText = '';
            let textArray = [];
            let counter = 0;
            _this.val().forEach(function (id, index) {
                selectOption.each(function () {
                    if ($(this).val().toString() === id.toString()) {
                        textArray.push($(this).text());
                        counter++;
                    }
                })
            });

            newText = textArray.join(', ');

            if (newText) {
                selectHead.text(newText);
            }

            if (counter > 0) {
                clearBtn.show();
                selectHead.attr('data-counter', '+' + counter);
            } else {
                //!selectHead.attr('data-counter', '');
                let clearText = '<span class="disabled-select-value">' + _this.children('option:disabled').text() + '</span>';
                selectHead.html(clearText);
            }

            searchInit();
        })

        _this.on('change', function () {
            if (_this.val()) {
                clearBtn.show();
            } else {
                clearBtn.hide();
            }

            const selectedValues = _this.val() || [];
            selectItem.each(function () {
                const isActive = selectedValues.includes($(this).data('value'));
                $(this).toggleClass('active', isActive);

                let newText = '';
                let textArray = [];
                let counter = 0;
                _this.val().forEach(function (id, index) {
                    selectOption.each(function () {
                        if ($(this).val().toString() === id.toString()) {
                            textArray.push($(this).text());
                            counter++;
                        }
                    })
                });

                newText = textArray.join(', ');
                if (newText) {
                    selectHead.text(newText);
                }

                if (counter > 0) {
                    clearBtn.show();
                    selectHead.attr('data-counter', '+' + counter);
                } else {
                    //! selectHead.attr('data-counter', '');
                    let clearText = '<span class="disabled-select-value">' + _this.children('option:disabled').text() + '</span>';
                    selectHead.html(clearText);
                }

            })

        });
    });

    $(document).mouseup(function (e) {
        if (e.which != 1) return false;
        var div = $(".new-select__list");
        var button = $('.new-select');
        if (!div.is(e.target) && div.has(e.target).length === 0) {
            if (!button.is(e.target) && button.has(e.target).length === 0) {
                $('.new-select__list').removeClass('active');
                $('.new-select').removeClass('on');
                $('body').removeClass('no-scroll');
            }
        }
    });
}






async function main(pointsList, jsonStyle) {

    $('.yandex-map-grid').removeClass('loading');
    // Waiting for all api elements to be loaded
    await ymaps3.ready;

    // Creating a custom control class for cluster management
    interface ClustererChangeControlProps {
        toggleClusterer: () => void;
        changePointsCount: (count: number) => void;
        updatePoints: () => void;
    }

    class ClustererChangeControl extends ymaps3.YMapComplexEntity<ClustererChangeControlProps> {
        private _element: HTMLDivElement;
        private _detachDom: () => void;

        // Method for create a DOM control element
        _createElement(props: ClustererChangeControlProps) {
            const { toggleClusterer, changePointsCount, updatePoints } = props;

            const clustererChange = document.createElement('div');
            clustererChange.classList.add('clusterer-change');

            const inputSection = document.createElement('div');
            inputSection.classList.add('clusterer-change__section');

            const inputLabel = document.createElement('div');
            inputLabel.classList.add('clusterer-change__input__label');
            inputLabel.textContent = 'Point count:';
            inputSection.appendChild(inputLabel);

            const inputField = document.createElement('input');
            inputField.type = 'number';
            inputField.classList.add('clusterer-change__input');
            inputField.value = '100';
            inputField.addEventListener('input', (e: Event) => {
                const target = e.target as HTMLInputElement;
                changePointsCount(+target.value);
            });
            inputSection.appendChild(inputField);

            const btnSection = document.createElement('div');
            btnSection.classList.add('clusterer-change__section');

            const updatePointsBtn = document.createElement('button');
            updatePointsBtn.type = 'button';
            updatePointsBtn.classList.add('clusterer-change__btn');
            updatePointsBtn.textContent = 'Update points';
            updatePointsBtn.addEventListener('click', updatePoints);
            btnSection.appendChild(updatePointsBtn);

            const toggleClustererBtn = document.createElement('button');
            toggleClustererBtn.type = 'button';
            toggleClustererBtn.classList.add('clusterer-change__btn');
            toggleClustererBtn.textContent = 'Delete/Add Clusterer';
            toggleClustererBtn.addEventListener('click', toggleClusterer);
            btnSection.appendChild(toggleClustererBtn);

            clustererChange.appendChild(inputSection);
            clustererChange.appendChild(btnSection);

            return clustererChange;
        }

        // Method for attaching the control to the map
        _onAttach() {
            this._element = this._createElement(this._props);
            this._detachDom = ymaps3.useDomContext(this, this._element, this._element);
        }

        // Method for detaching control from the map
        _onDetach() {
            // this._detachDom();
            //this._detachDom = null;
            // this._element = null;
        }
    }


    // Create a custom marker class with a popup



    const { YMap, YMapCollection, YMapDefaultSchemeLayer, YMapFeatureDataSource, YMapLayer, YMapMarker, YMapControls, YMapControl } =
        ymaps3;

    // Load the package with the cluster, extract the classes for creating clusterer objects and the clustering method
    const { YMapClusterer, clusterByGrid } = await ymaps3.import('@yandex/ymaps3-clusterer@0.0.1');

    // Declare number of points in the clusterer
    let pointsCount = 0;





    let baseCenter = [
        40.405808,
        56.137340
    ];

    if (pointsList[0] && pointsList[0].geometry && pointsList[0].geometry.coordinates) {

        baseCenter = pointsList[0].geometry.coordinates;
    }

    if (!window.map) {

        let defaultZoom = 13;

        if (window.detail && !window.showAll) {
            defaultZoom = 19;
        }

        window.map = new YMap(document.getElementById('yandex-map'), {
            location: {
                center: baseCenter,
                zoom: defaultZoom,
            },
            behaviors: ['drag', 'pinchZoom', 'dblClick'],
            copyrights: false,

        });


        // Включение и отключение scrollZoom через обновление параметров карты
        const enableScrollZoom = () => {
            console.log('enableScrollZoom');            
            window.map.update({
                behaviors: ['drag', 'pinchZoom', 'dblClick', 'scrollZoom'] // Добавляем scrollZoom
            });
        };

        const disableScrollZoom = () => {
            console.log('disableScrollZoom');
            window.map.update({
                behaviors: ['drag', 'pinchZoom', 'dblClick'] // Исключаем scrollZoom
            });
        };

        const mapElement = document.querySelector('.map-contaner');

        let zoomTimeout;

       /* mapElement.addEventListener('mouseenter', () => {
            clearTimeout(zoomTimeout);
            zoomTimeout = setTimeout(enableScrollZoom, 1000); // Включаем зум по скроллу через 1.5 секунды
        });

        mapElement.addEventListener('mouseleave', () => {
            clearTimeout(zoomTimeout); // Отменяем таймаут на включение, если курсор ушел с карты до истечения времени
            zoomTimeout = setTimeout(disableScrollZoom, 300); // Отключаем зум по скроллу через 1 секунду
        });*/

        // Create and add to the map a layer with a map schema, data sources, a layer of markers
        window.map.addChild(new YMapDefaultSchemeLayer({}))
            .addChild(new YMapFeatureDataSource({ id: 'clusterer-source' }))
            .addChild(new YMapLayer({ source: 'clusterer-source', type: 'markers', zIndex: 1800 }));
        window.map.addChild(new YMapDefaultSchemeLayer({
            customization: jsonStyle
        }));

        document.querySelector('.js-zoom-plus').addEventListener('click', function () {
            let oldZoom = window.map.zoom;
            let newZoom = oldZoom + 1;
            let NEW_LOCATION_CENTER: YMapLocationRequest = {
                zoom: newZoom
            };

            changeMapPosition(NEW_LOCATION_CENTER, { tilt: 0 });
        });

        document.querySelector('.js-zoom-minus').addEventListener('click', function () {
            let oldZoom = window.map.zoom;
            let newZoom = oldZoom - 1;
            let NEW_LOCATION_CENTER: YMapLocationRequest = {
                zoom: newZoom
            };

            changeMapPosition(NEW_LOCATION_CENTER, { tilt: 0 });
        });

    }


    /**
        * Получение масштаба
        * @param {[Array, Array]} bounds
        * @param {YMap} map
        * @param {Boolean} inscribe вписывать область в карту
        * @param {Boolean} floor округляем результат в меньшую сторону
        * @returns {Number}
        */
    function getScale(bounds, map, inscribe, floor) {
        if (typeof inscribe === "undefined") {
            inscribe = true;
        }
        if (typeof floor === "undefined") {
            floor = false;
        }
        var pixelBounds = toGlobalPixelBounds(bounds, 0);
        // 1e-10 чтобы не было деления на 0
        var deltaX = Math.max(Math.abs(pixelBounds[1][0] - pixelBounds[0][0]), 1e-10);
        var deltaY = Math.max(Math.abs(pixelBounds[1][1] - pixelBounds[0][1]), 1e-10);
        var logX = Math.log(map.size.x / deltaX) * Math.LOG2E;
        var logY = Math.log(map.size.y / deltaY) * Math.LOG2E;
        var result = Math.min(Math.max(0, inscribe ? Math.min(logX, logY) : Math.max(logX, logY)), map.zoomRange.max);
        let zoom = floor ? Math.floor(result + 1e-10) : result;



        if (zoom > 15 && (window.detail && !window.showAll)) {
            zoom = 15;
        }

        if (window.detail && !window.showAll) {
            zoom = 18;
        }



        return zoom * 0.95;
    }
    function toGlobalPixelBounds(geoBounds, zoom) {
        if (typeof zoom === "undefined") {
            zoom = 0;
        }

        var lowerCorner = toGlobalPixels(geoBounds[0], zoom);
        var upperCorner = toGlobalPixels(geoBounds[1], zoom);
        var projectionCycled = [true, false];
        var worldSize = calculateWorldSize(zoom);
        var result = [lowerCorner.slice(), upperCorner.slice()];
        if (lowerCorner[0] > upperCorner[0]) {
            if (projectionCycled[0]) {
                result[0][0] = lowerCorner[0];
                result[1][0] = upperCorner[0] + worldSize;
            } else {
                result[0][0] = upperCorner[0];
                result[1][0] = lowerCorner[0];
            }
        }
        if (lowerCorner[1] > upperCorner[1]) {
            if (projectionCycled[1]) {
                result[0][1] = lowerCorner[1];
                result[1][1] = upperCorner[1] + worldSize;
            } else {
                result[0][1] = upperCorner[1];
                result[1][1] = lowerCorner[1];
            }
        }
        return result;
    }

    function toGlobalPixels(point, zoom) {
        var radius = 6378137;
        var equator = 2 * Math.PI * radius;
        var subequator = 1 / equator;
        var pixelsPerMeter = 256 * subequator;
        var halfEquator = equator / 2;
        var currentZoom = 0;

        if (zoom != currentZoom) {
            pixelsPerMeter = Math.pow(2, zoom + 8) * subequator;
            currentZoom = zoom;
        }

        var mercatorCoords = geoToMercator(point);
        return [
            (halfEquator + mercatorCoords[0]) * pixelsPerMeter,
            (halfEquator - mercatorCoords[1]) * pixelsPerMeter
        ];
    }

    function geoToMercator(geo) {
        return [
            longitudeToX(geo[0]),
            latitudeToY(geo[1])
        ];
    }


    function longitudeToX(lng) {
        var radius = 6378137;
        var c_pi180 = Math.PI / 180;
        var longitude = cycleRestrict(lng * c_pi180, -Math.PI, Math.PI);
        return radius * longitude;
    }

    function latitudeToY(lat) {
        var radius = 6378137;
        var e = 0.0818191908426;
        var c_pi180 = Math.PI / 180;
        var c_180pi = 180 / Math.PI;
        var epsilon = 1e-10;
        // epsilon чтобы не получить (-)Infinity
        var latitude = restrict(lat, -90 + epsilon, 90 - epsilon) * c_pi180;
        var esinLat = e * Math.sin(latitude);

        // Для широты -90 получается 0, и в результате по широте выходит -Infinity
        var tan_temp = Math.tan(Math.PI * 0.25 + latitude * 0.5);
        var pow_temp = Math.pow(Math.tan(Math.PI * 0.25 + Math.asin(esinLat) * 0.5), e);
        var U = tan_temp / pow_temp;

        return radius * Math.log(U);
    }

    function restrict(value, min, max) {
        return Math.max(Math.min(value, max), min);
    }
    function cycleRestrict(value, min, max) {
        if (value == Number.POSITIVE_INFINITY) {
            return max;
        } else if (value == Number.NEGATIVE_INFINITY) {
            return min;
        }
        return value - Math.floor((value - min) / (max - min)) * (max - min);
    }
    function calculateWorldSize(zoom) {
        return Math.pow(2, zoom + 8);
    }

    // Функция для вычисления границ, в которые должны вписаться все маркеры
    function calculateBounds(coordinates: number[][]): [number[], number[]] {
        let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;

        coordinates.forEach(coord => {
            minX = Math.min(minX, coord[0]);
            minY = Math.min(minY, coord[1]);
            maxX = Math.max(maxX, coord[0]);
            maxY = Math.max(maxY, coord[1]);
        });

        return [[minX, minY], [maxX, maxY]];
    }




    // Создаем массив координат всех маркеров
    let coordinates = pointsList.map(point => point.geometry.coordinates);

    // Вычисляем средние координаты всех маркеров
    let center = coordinates.reduce((sum, coord) => {
        return [sum[0] + coord[0], sum[1] + coord[1]];
    }, [0, 0]).map(n => n / coordinates.length);

    // Рассчитываем оптимальный зум
    // Вычисляем границы
    let bounds = calculateBounds(coordinates);

    //console.log(bounds);


    let zoom = getScale(bounds, window.map, true, true);
    //console.log(zoom);

    if (!window.detail) {
        let rightCoord = bounds[1];
        let newCenter = [0, 0];
        newCenter[0] = center[0] + ((rightCoord[0] - center[0]) * 0.7);
        newCenter[1] = center[1];
        center = newCenter;


    }






    let NEW_LOCATION_CENTER: YMapLocationRequest = {
        center: center,
        zoom: zoom
    };

    changeMapPosition(NEW_LOCATION_CENTER, { tilt: 0 });






    // You can set any markup for the marker and for the cluster
    const contentPin = document.createElement('div');
    contentPin.classList.add('pin-container');
    const contentPinWrapper = document.createElement('div');
    contentPinWrapper.classList.add('pin-wrapper');
    contentPinWrapper.innerHTML = `<svg class="pin" xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64" fill="none">
    <rect class='rect' width="15.8829" height="2.11592" rx="1.05796" transform="matrix(-0.999997 -0.00224681 0.0010868 0.999999 40.874 53.8881)" fill="#191B1D"/>
    <path d="M56.2554 22.0094L40.1122 53.9643L25.9731 54.004L12.212 21.1971L56.2554 22.0094Z" fill="url(#paint0_linear_210_2190)"/>
    <defs>
    <linearGradient id="paint0_linear_210_2190" x1="33.0553" y1="54.8309" x2="34.5373" y2="22.432" gradientUnits="userSpaceOnUse">
    <stop stop-color="#3A66FF"/>
    <stop offset="1" stop-color="#3A66FF" stop-opacity="0"/>
    </linearGradient>
    </defs>
    </svg>`;
    contentPin.appendChild(contentPinWrapper);


    const marker = (feature: Feature) => {
        let contentPinClone = contentPin.cloneNode(true) as HTMLElement;



        const popupContent = document.createElement("div");
        popupContent.classList.add('pin-popup');
        popupContent.innerHTML = feature.popup || '';
        contentPinClone.appendChild(popupContent);
        const pinWrapperElement = contentPinClone.querySelector('.pin-wrapper');
        if (feature.double) {
            let otherSide = `<svg class="pin double-pin" width="48" height="68" viewBox="0 0 48 68" fill="none" xmlns="http://www.w3.org/2000/svg">
            <path class='rect' d="M17.0572 32.8547L30.9314 32.8859C31.5202 32.8872 31.9981 33.361 31.9987 33.9441C31.9993 34.5273 31.5225 34.9989 30.9337 34.9976L17.0595 34.9664C16.4707 34.9651 15.9928 34.4913 15.9922 33.9082C15.9915 33.3251 16.4684 32.8534 17.0572 32.8547Z" fill="#191B1D"/>
            <path d="M47.2553 1.00944L31.1121 32.9643L16.973 33.004L3.21191 0.197144L47.2553 1.00944Z" fill="url(#paint0_linear_1102_112)"/>
            <path d="M0.461892 66.7388L16.7855 34.8757L30.9246 34.9159L44.5 67.8L0.461892 66.7388Z" fill="url(#paint1_linear_1102_112)"/>
            <defs>
            <linearGradient id="paint0_linear_1102_112" x1="24.0552" y1="33.8309" x2="25.5372" y2="1.43204" gradientUnits="userSpaceOnUse">
            <stop stop-color="#3A66FF"/>
            <stop offset="1" stop-color="#3A66FF" stop-opacity="0"/>
            </linearGradient>
            <linearGradient id="paint1_linear_1102_112" x1="23.8472" y1="34.049" x2="22.182" y2="66.439" gradientUnits="userSpaceOnUse">
            <stop stop-color="#3A66FF"/>
            <stop offset="1" stop-color="#3A66FF" stop-opacity="0"/>
            </linearGradient>
            </defs>
            </svg>
            
            `;
            pinWrapperElement.innerHTML = otherSide;
        }
        pinWrapperElement.setAttribute('degress', feature.degress);
        pinWrapperElement.style.rotate = `${feature.degress}deg`;
        //find pin wrapper


        pinWrapperElement.addEventListener('click', (e: Event) => {
            let w = $(window).width();
            //toggle class active
            const target = e.currentTarget as HTMLElement;
            const pin = contentPinClone;
            if (pin) {
                $('.pin-container').not(pin).removeClass('active');
                pin.classList.toggle('active');
                $('.pin-container').not(pin).closest('.ymaps3x0--marker').removeClass('active');
                $(pin).closest('.ymaps3x0--marker').toggleClass('active');
            }
            if (pin) {

                let baseCenter = feature.geometry.coordinates;

                

                // Рассчитываем оптимальный зум
                // Вычисляем границы
                let bounds = window.map.bounds;
                let overlayObject = document.querySelector('.map-overlay');
                let zoom = getScale(bounds, window.map, true, true);
                //let center = baseCenter;
                let rightCoord = bounds[1];
                let leftCoord = bounds[0];
                let newCenter = center;

                let mapWidthCoords = Math.abs(rightCoord[0] - leftCoord[0]);
                let mapHeightCoords = Math.abs(rightCoord[1] - leftCoord[1]);

                newCenter[0] = baseCenter[0] + (mapWidthCoords * 0.2);
                newCenter[1] = baseCenter[1] + (mapHeightCoords * 0.2);

                if (overlayObject.classList.contains('deactive')) {
                    //console.log('Оверлей скрыт');
                    newCenter = feature.geometry.coordinates;

                    newCenter[1] = baseCenter[1] + (mapHeightCoords * 0.2);
                } else {
                    //console.log('Оверлей отображен');
                    //newCenter = baseCenter;
                }
                /*console.log(baseCenter);
                
                console.log(mapWidthCoords);*/

                let w = $(window).width();

                if(w<=991){
                    newCenter = feature.geometry.coordinates;
                }
                
                
                
                

                let locationData = {
                    center: newCenter,
                    //zoom: 18,
                    duration: 500
                };


                window.map.update(
                    {
                        location: locationData,
                    }
                );


                //window.swiperDinamic
                let itemID = feature.id;
                window.NotNeedZoom = true;
                let swiper = window.swiperDinamic;
                if (swiper) {
                    let slides = swiper.slides;
                    let indexToSwitch = -1;

                    for (let i = 0; i < slides.length; i++) {
                        if (slides[i].getAttribute('data-id') === itemID) {
                            indexToSwitch = i;
                            break;
                        }
                    }

                    if (indexToSwitch !== -1) {
                        swiper.slideTo(indexToSwitch);
                    }
                }
            }
        })
        return new YMapMarker(
            {
                coordinates: feature.geometry.coordinates,
                source: 'clusterer-source',
            },
            contentPinClone
        );
    };

    // As for ordinary markers, we declare a cluster rendering function that also returns an Entity element.
    const cluster = (coordinates: LngLat, features: Feature[]) => {

        let localCircle = circle(features.length, features).cloneNode(true) as HTMLElement
        localCircle.addEventListener('click', (e: Event) => {
            const target = e.currentTarget as HTMLElement;
            //console.log('click');
            // console.log(features);    

            // Создаем массив координат всех маркеров
            let coordinates = features.map(point => point.geometry.coordinates);

            // Вычисляем средние координаты всех маркеров
            let center = coordinates.reduce((sum, coord) => {
                return [sum[0] + coord[0], sum[1] + coord[1]];
            }, [0, 0]).map(n => n / coordinates.length);

            // Рассчитываем оптимальный зум
            // Вычисляем границы
            let bounds = calculateBounds(coordinates);

            let zoom = getScale(bounds, window.map, true, true);
            //console.log(zoom);

            if (!window.detail) {
                let rightCoord = bounds[1];
                let newCenter = [0, 0];
                newCenter[0] = center[0] + ((rightCoord[0] - center[0]) * 0.7);
                newCenter[1] = center[1];
                center = newCenter;
            }


            let NEW_LOCATION_CENTER: YMapLocationRequest = {
                center: center,
                zoom: zoom
            };

            changeMapPosition(NEW_LOCATION_CENTER, { tilt: 0 });



        })
        return new YMapMarker(
            {
                coordinates,
                source: 'clusterer-source'
            },
            localCircle
        );
    }




    function circle(count: number, features) {
        const circle = document.createElement('div');
        circle.classList.add('circle');
        circle.innerHTML = `
            <div class="circle-content">
                <span class="circle-text">${count}</span>
            </div>
        `;



        return circle;
    }

    /* We create a clusterer object and add it to the map object.
    As parameters, we pass the clustering method, an array of features, the functions for rendering markers and clusters.
    For the clustering method, we will pass the size of the grid division in pixels. */




    let clusterer = new YMapClusterer({
        method: clusterByGrid({ gridSize: 32 }),
        features: pointsList,
        marker,
        cluster
    });
    if (window.Coll) {
        window.map.removeChild(window.Coll);
        window.Coll = null;
    }
    // 

    //console.log(clusterer);





    window.Coll = new YMapCollection();
    window.Coll.addChild(clusterer);


    // window.map.addChild(window.clusterer);
    window.map.addChild(window.Coll);


    function changeMapPosition(location, camera) {
        window.map.update({ location: { ...location, duration: 500 } });
    }

    function changeCenterBtnHandler(NEW_LOCATION_CENTER) {
        changeMapPosition(NEW_LOCATION_CENTER, { tilt: (45 * Math.PI) / 180 });
    }


    $('.yandex-map--item').click(function () {
        let lat = $(this).data('lt');
        let lng = $(this).data('ln');

        let centerObject = {
            center: [lng, lat],
            zoom: 12
        };

        $('.yandex-map--item').not(this).removeClass('active');
        $(this).addClass('active');

        changeCenterBtnHandler(centerObject)
        if ($(window).width() <= 991) {
            $('html, body').animate({
                scrollTop: $('#yandex-map').offset().top
            }, 300);
        }
    });


}


