import { attributeSelector } from '../common/selector-utilities';

const ATTRIBUTE = Object.freeze({
    CONFIG: 'data-outdooractive-api-config',
    CLIENT: 'data-outdooractive-api-config.client',
    API_KEY: 'data-outdooractive-api-config.api-key',
    LANGUAGE: 'data-outdooractive-api-config.language',
    BASE_URL: 'data-outdooractive-api-config.base-url',
});

/**
 * Shared promise for loading outdoor active.
 * This variable must only be used inside of `loadOutdoorActive`.
 * If you need this promise plaese retrieve it from that method.
 *
 * @type {Promise}
 * @private
 */
let outdoorActiveTrackingPromise;
const apiUrl = '//www.outdooractive.com/alpportal/oa_head.js';
const loadingErrorListeners = [];

/**
 * @param {object} object
 * @returns {string}
 */
function objectToQueryString(object) {
    return Object.keys(object)
        .filter(key => !!object[key])
        .map(key => `${key}=${encodeURIComponent(object[key])}`)
        .join('&');
}

/**
 * @param {HTMLElement} configuration
 * @param {string} callbackName
 * @returns {string}
 */
function getApiUrl(configuration, callbackName) {
    const query = {
        proj: configuration.getAttribute(ATTRIBUTE.CLIENT),
        key: configuration.getAttribute(ATTRIBUTE.API_KEY),
        lang: configuration.getAttribute(ATTRIBUTE.LANGUAGE) || document.documentElement.lang || 'de',
        callback: callbackName,
    };
    return `${apiUrl}?${objectToQueryString(query)}`;
}


/**
 * Returns a promise that is resolved with the outdoor active instance.
 *
 * @returns {Promise}
 */
export function loadOutdoorActive() {
    if (!outdoorActiveTrackingPromise) {
        const configuration = document.querySelector(attributeSelector(ATTRIBUTE.CONFIG));
        if (!configuration) {
            console.warn('No OA tracking configuration detected!');
            return Promise.reject('No OA tracking configuration detected!');
        }

        const callbackName = `__outdoorActiveCallback__${Math.random().toString(16).substr(2)}`;
        outdoorActiveTrackingPromise = new Promise((resolve, reject) => {
            window[callbackName] = () => resolve(window.oa);

            const script = document.createElement('script');
            script.addEventListener('error', err => {
                loadingErrorListeners.forEach(cb => cb(err));
                reject(err);
            });
            script.src = getApiUrl(configuration, callbackName);
            document.head.appendChild(script);
        });
    }

    return outdoorActiveTrackingPromise;
}

/**
 * @param {Function} callback
 * @returns {void}
 */
export function onOutdoorActiveLoadingError(callback) {
    loadingErrorListeners.push(callback);
}
