/**
 * @typedef {Object} PopupManagerArg 
 * @property {ol.Map} map - ol-карта
 * @property {HTMLElement} popup_div - контейнер всплывающего окна
 * @property {HTMLElement} [popup_close] - закрывашка
 * @property {(feature: ol.Feature) => void} map_on - поведение при нажатии на map
 * @property {[number, number]} offset - смещение popup
 */

/**
 * Управление и создание ol-popup
 * 
 * @class PopupManager
 * @property {ol.Map} map - ol-карта
 * @property {HTMLElement} popup_div - контейнер всплывающего окна
 * @property {HTMLElement} [popup_close] - закрывашка
 * @property {(feature: ol.Feature) => void} map_on - поведение при нажатии на map
 */
class PopupManager {
    /**
     * @param {PopupManagerArg} args
     */
    constructor ({map, popup_div, popup_close, map_on = (feature) => {}, offset = [0, 0]}) {
        /** Безопасный вызов */
        recovery(
            /** 
             * @function
             * @param {PopupManager} self 
             */ 
            self => {
                /** Инъекция карты */
                if(map && map instanceof ol.Map) self.map = map
                else throw new Error("Аргумент 'map' невалиден")

                /** Инъекция поведения при нажатии на map */
                this.set_map_on(map_on)

                /** Инъекция popup-элемента */
                if(popup_div && popup_div instanceof HTMLElement) 
                    self.popup_div = popup_div
                else throw new Error("Аргумент 'popup_div' невалиден")

                /** Инициализация popup-элемента */
                self.overlay = new ol.Overlay({
                    element: self.popup_div,
                    autoPan: true,
                    offset: offset
                })

                /** Регристрация overlay */
                self.map.addOverlay(self.overlay)

                /** Добавление поведения при нажатии на карту */
                self.map.on('click', evt => {
                    /** Получение данных маркера */
                    const feature = self.map.forEachFeatureAtPixel(
                        evt.pixel, 
                        (feature, _) => feature,
                        { hitTolerance: 8 }
                    )
                    if(feature) {
                        /** Вызов переданной функции */
                        self.map_on(feature)

                        /** Прилинковка popup  */
                        self.set_popup(feature.getGeometry().getCoordinates())
                    } else {
                        /** Олинковка popup */
                        self.set_popup()
                    }
                })

                /** При нажатии не на маркеры убрать popup */
                document.addEventListener('click', event => {
                    if (!event.target.closest('.ol-viewport') && !event.target.closest('.popup')) {
                        self.set_popup()
                    }
                })
                
                /** Инъекция и инициалиазция закрывашки (если есть) */
                if(popup_close) {
                    /** Инъекция закрывашки */
                    if (popup_close instanceof HTMLElement) self.popup_close = popup_close
                    else throw new Error("Аргумент 'popup_close' невалиден")

                    /** Инициаилазиця закрывашки */
                    self.popup_close.onclick = function () {
                        /** Отлинковка от координат */
                        self.set_popup()
                        /** Скрытие */
                        popup_close.blur()
                        return false
                    }
                }
            },
            (...e) => {
                console.log("Ошибка при инициалиазции PopupManager");
                e.forEach(er => {throw er});
            }
        ) (this)
    }

    /** 
     * @function
     * @param {[number, number] | undefined} [coord] - координаты привязки
     */
    set_popup = recovery(
        (coord = undefined) => this.overlay.setPosition(coord),
        (...e) => {
            console.log("Ошибка скрытии popup (PopupManager.set_popup)");
            e.forEach(er => {throw er});
        }
    )

    /**
     * Изменение поведения при нажатии на map
     * @function
     * @param {(feature: Object) => void} map_on - поведение при нажатии на map
     */
    set_map_on = recovery(
        map_on => this.map_on = map_on,
        (...e) => {
            console.log("Ошибка при инициалиазции PopupManager.set_map_on");
            e.forEach(er => {throw er});
        }
    )
}