import RSVP from 'rsvp';
import Service, {inject as service} from '@ember/service';
import classic from 'ember-classic-decorator';
import config from 'ghost-admin/config/environment';
import {prefixAssetUrl} from 'ghost-admin/utils/asset-base';

@classic
export default class LazyLoaderService extends Service {
    @service ajax;

    // This is needed so we can disable it in unit tests
    testing = undefined;

    scriptPromises = null;

    init() {
        super.init(...arguments);
        this.scriptPromises = {};

        if (this.testing === undefined) {
            this.testing = config.environment === 'test';
        }
    }

    loadScript(key, url) {
        if (this.testing) {
            return RSVP.resolve();
        }

        if (this.scriptPromises[key]) {
            return this.scriptPromises[key];
        }

        let scriptPromise = new RSVP.Promise((resolve, reject) => {
            let script = document.createElement('script');
            script.type = 'text/javascript';
            script.async = true;
            script.src = prefixAssetUrl(url);

            let el = document.getElementsByTagName('script')[0];
            el.parentNode.insertBefore(script, el);

            script.addEventListener('load', () => {
                resolve();
            });

            script.addEventListener('error', () => {
                reject(new Error(`${url} failed to load`));
            });
        });

        this.scriptPromises[key] = scriptPromise;

        return scriptPromise;
    }

    loadStyle(key, url, alternate = false) {
        if (this.testing || document.querySelector(`#${key}-styles`)) {
            return RSVP.resolve();
        }

        return new RSVP.Promise((resolve, reject) => {
            let link = document.createElement('link');
            link.id = `${key}-styles`;
            link.rel = alternate ? 'alternate stylesheet' : 'stylesheet';
            link.href = prefixAssetUrl(url);
            link.onload = () => {
                link.onload = null;
                if (alternate) {
                    // If stylesheet is alternate and we disable the stylesheet before injecting into the DOM,
                    // the onload handler never gets called. Thus, we should disable the link after it has finished loading
                    link.disabled = true;
                }
                resolve();
            };
            link.onerror = reject;

            if (alternate) {
                link.title = key;
            }

            // Try to insert lazy loaded styles after the first set of links in
            // the head to ensure any styles related to Ember are loaded before
            // the React admin shell. 
            let existingLink = document.querySelector('head link[rel="stylesheet"]:first-of-type');
            if (existingLink) {
                while (existingLink.nextElementSibling && existingLink.nextElementSibling.tagName === 'LINK') {
                    existingLink = existingLink.nextElementSibling;
                }
                existingLink.insertAdjacentElement('afterend', link);
            } else {
                document.querySelector('head').appendChild(link);
            }
        });
    }
}
