'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var mockDoc = require('../mock-doc');
var runtime = require('../runtime');

const queuedTicks = [];
const queuedWriteTasks = [];
const moduleLoaded = new Map();
const queuedLoadModules = [];
const caughtErrors = [];
const consoleError = (e) => {
    caughtErrors.push(e);
};
function resetTaskQueue() {
    queuedTicks.length = 0;
    queuedWriteTasks.length = 0;
    moduleLoaded.clear();
    queuedLoadModules.length = 0;
    caughtErrors.length = 0;
}
const tick = {
    then(cb) {
        queuedTicks.push(cb);
    }
};
function flushTicks() {
    return new Promise((resolve, reject) => {
        function drain() {
            try {
                if (queuedTicks.length > 0) {
                    const writeTasks = queuedTicks.slice();
                    queuedTicks.length = 0;
                    let cb;
                    while ((cb = writeTasks.shift())) {
                        cb(Date.now());
                    }
                }
                if (queuedTicks.length > 0) {
                    process.nextTick(drain);
                }
                else {
                    resolve();
                }
            }
            catch (e) {
                reject(`flushTicks: ${e}`);
            }
        }
        process.nextTick(drain);
    });
}
function writeTask(cb) {
    queuedWriteTasks.push(cb);
}
function flushQueue() {
    return new Promise((resolve, reject) => {
        function drain() {
            try {
                if (queuedWriteTasks.length > 0) {
                    const writeTasks = queuedWriteTasks.slice();
                    queuedWriteTasks.length = 0;
                    let cb;
                    while ((cb = writeTasks.shift())) {
                        cb(Date.now());
                    }
                }
                if (queuedWriteTasks.length > 0) {
                    process.nextTick(drain);
                }
                else {
                    resolve();
                }
            }
            catch (e) {
                reject(`flushQueue: ${e}`);
            }
        }
        process.nextTick(drain);
    });
}
async function flushAll() {
    while (queuedTicks.length > 0 || queuedLoadModules.length > 0 || queuedWriteTasks.length > 0) {
        await flushTicks();
        await flushLoadModule();
        await flushQueue();
    }
    if (caughtErrors.length > 0) {
        throw caughtErrors[0];
    }
}
function loadModule(cmpMeta, _hostRef, _hmrVersionId) {
    return new Promise(resolve => {
        queuedLoadModules.push({
            bundleId: cmpMeta.$lazyBundleIds$,
            resolve: () => resolve(moduleLoaded.get(cmpMeta.$lazyBundleIds$))
        });
    });
}
function flushLoadModule(bundleId) {
    return new Promise((resolve, reject) => {
        try {
            process.nextTick(() => {
                if (bundleId != null) {
                    for (let i = 0; i < queuedLoadModules.length; i++) {
                        if (queuedLoadModules[i].bundleId === bundleId) {
                            queuedLoadModules[i].resolve();
                            queuedLoadModules.splice(i, 1);
                            i--;
                        }
                    }
                }
                else {
                    let queuedLoadModule;
                    while ((queuedLoadModule = queuedLoadModules.shift())) {
                        queuedLoadModule.resolve();
                    }
                }
                resolve();
            });
        }
        catch (e) {
            reject(`flushLoadModule: ${e}`);
        }
    });
}
function registerModule(bundleId, Cstr) {
    moduleLoaded.set(bundleId, Cstr);
}

const win = mockDoc.setupGlobal(global);
const getWin = (_) => win;
const getDoc = (_) => getWin().document;
const getHead = (_) => getDoc().head;
const hostRefs = new Map();
const styles = new Map();
const plt = {
    $isTmpDisconnected$: false,
    $queueCongestion$: 0,
    $queuePending$: false,
};
const supportsShadowDom = true;
const supportsListenerOptions = true;
const supportsConstructibleStylesheets = false;
function resetPlatform() {
    mockDoc.resetWindow(win);
    hostRefs.clear();
    styles.clear();
    plt.$isTmpDisconnected$ = false;
    if (plt.$orgLocNodes$ != null) {
        plt.$orgLocNodes$.clear();
        plt.$orgLocNodes$ = undefined;
    }
    resetTaskQueue();
}
const getHostRef = (elm) => hostRefs.get(elm);
const registerInstance = (lazyInstance, hostRef) => hostRefs.set(hostRef.$lazyInstance$ = lazyInstance, hostRef);
const registerHost = (elm) => {
    const hostRef = {
        $stateFlags$: 0,
        $hostElement$: elm,
        $instanceValues$: new Map(),
    };
    hostRef.$onReadyPromise$ = new Promise(r => hostRef.$onReadyResolve$ = r);
    hostRefs.set(elm, hostRef);
};
const Context = {
    isServer: false,
    enableListener: () => console.log('TODO'),
    queue: {}
};
const getContext = (elm, context) => {
    if (context === 'window') {
        return getWin(elm);
    }
    if (context === 'document') {
        return getDoc(elm);
    }
    if (context === 'isServer') {
        return true;
    }
    return Context[context];
};

Object.defineProperty(exports, 'Host', {
    enumerable: true,
    get: function () {
        return runtime.Host;
    }
});
Object.defineProperty(exports, 'bootstrapLazy', {
    enumerable: true,
    get: function () {
        return runtime.bootstrapLazy;
    }
});
Object.defineProperty(exports, 'createEvent', {
    enumerable: true,
    get: function () {
        return runtime.createEvent;
    }
});
Object.defineProperty(exports, 'getConnect', {
    enumerable: true,
    get: function () {
        return runtime.getConnect;
    }
});
Object.defineProperty(exports, 'getElement', {
    enumerable: true,
    get: function () {
        return runtime.getElement;
    }
});
Object.defineProperty(exports, 'getValue', {
    enumerable: true,
    get: function () {
        return runtime.getValue;
    }
});
Object.defineProperty(exports, 'h', {
    enumerable: true,
    get: function () {
        return runtime.h;
    }
});
Object.defineProperty(exports, 'insertVdomAnnotations', {
    enumerable: true,
    get: function () {
        return runtime.insertVdomAnnotations;
    }
});
Object.defineProperty(exports, 'parsePropertyValue', {
    enumerable: true,
    get: function () {
        return runtime.parsePropertyValue;
    }
});
Object.defineProperty(exports, 'patchDynamicImport', {
    enumerable: true,
    get: function () {
        return runtime.patchDynamicImport;
    }
});
Object.defineProperty(exports, 'setValue', {
    enumerable: true,
    get: function () {
        return runtime.setValue;
    }
});
exports.consoleError = consoleError;
exports.flushAll = flushAll;
exports.flushLoadModule = flushLoadModule;
exports.flushQueue = flushQueue;
exports.flushTicks = flushTicks;
exports.getContext = getContext;
exports.getDoc = getDoc;
exports.getHead = getHead;
exports.getHostRef = getHostRef;
exports.getWin = getWin;
exports.loadModule = loadModule;
exports.plt = plt;
exports.registerHost = registerHost;
exports.registerInstance = registerInstance;
exports.registerModule = registerModule;
exports.resetPlatform = resetPlatform;
exports.resetTaskQueue = resetTaskQueue;
exports.styles = styles;
exports.supportsConstructibleStylesheets = supportsConstructibleStylesheets;
exports.supportsListenerOptions = supportsListenerOptions;
exports.supportsShadowDom = supportsShadowDom;
exports.tick = tick;
exports.win = win;
exports.writeTask = writeTask;
