/*eslint-disable*/
importScripts('/lib/constructors/EventEmitter.js');
self.$$frameworkFlag = {};
let channelId;
const shouldReturnResult = false;
let requestId;
let payloads = [];
let isCommandsDebugger = false;

let origConsole = self.console;
let clearConsole = self.console.clear.bind(self.console);
let eventEmitter = new EventEmitter();

const navigator = undefined;
let debuggerInteract;


function setDebuggerInteract(setStatus) {
    if (setStatus && AtomEngine) {
        // 为了调试方便，间隔一段时间发送事件
        debuggerInteract = setInterval(() => {
            AtomEngine.dispatchEvent(new AtomEngine.EventTarget.Event(AtomEngine, 'debuggerInteract'));
        }, 3000);
    }
    else if (!setStatus && debuggerInteract){
        clearInterval(debuggerInteract);
    }
}

function postData(payload) {
    payloads.push(payload)
    try {
        postMessage(payload);
    }
    catch (e) {
        self.console.warn(`CallNative with some non-json data:`, payload);
        payload = JSON.parse(JSON.stringify(payload));
        postMessage(payload);
    }
}

let _rewriteLog = function () {
    let LEVELS = ['error', 'warn', 'info', 'log', 'debug'];
    let backupConsole = {
        error: origConsole.error,
        warn: origConsole.warn,
        info: origConsole.info,
        log: origConsole.log,
        debug: origConsole.debug
    };

    function resetConsole() {
        self.console.error = backupConsole.error;
        self.console.warn = backupConsole.warn;
        self.console.info = backupConsole.info;
        self.console.log = backupConsole.log;
        self.console.debug = backupConsole.debug;
        self.console.time = origConsole.time;
        self.console.timeEnd = origConsole.timeEnd;
    }

    function noop() {}
    return function (logLevel) {
        resetConsole();
        LEVELS.slice(LEVELS.indexOf(logLevel) + 1).forEach(function (level) {
            self.console[level] = noop;
        })
    }
}();

onmessage = function (message) {
    eventEmitter.emit(message.data && message.data.method, message.data);
};

self.callNativeModule = function () {
    let message = {
        method: 'AtomDebug.syncCall',
        params: {
            method: 'callNativeModule',
            args: Array.prototype.slice.call(arguments)
        },
        channelId: channelId
    }
    let result = syncRequest(message);
    if (shouldReturnResult && requestId) {
        postData({
            id: requestId,
            result: null,
            error: {
                errorCode: 0
            }
        });
    }
    if (result && result.error) {
        self.console.error(result.error);
    }
    else return result && result.ret;
}

self.callNativeComponent = function () {
    let message = {
        method: 'AtomDebug.syncCall',
        params: {
            method: 'callNativeComponent',
            args: Array.prototype.slice.call(arguments)
        },
        channelId: channelId
    }
    let result = syncRequest(message);
    if (result.error) {
        self.console.error(result.error);
    }
    else return result.ret;
};

self.callNative = function (instance, tasks, callback) {
    for (let i = 0; i < tasks.length; i++) {
        let task = tasks[i];
        if (task.method == 'addElement') {
            for (let key in task.args[1].style) {
                if (Number.isNaN(task.args[1].style[key])) {
                    self.console.error('invalid value [NaN] for style [' + key + ']', task);                
                }
            }
        }
    }
    let payload = {
        method: 'AtomDebug.callNative',
        params: {
            instance: instance,
            tasks: tasks,
            callback: callback
        }
    };
    postData(payload);
};

self.responseInitJsFramework = function (result) {
    let payload = {
        method: 'AtomDebug.responseInitJsFramework',
        params: {
            result: result
        }
    };
    postData(payload);
};

self.responseGetConsumeQueue = function (result) {
    let payload = {
        method: 'AtomDebug.responseGetConsumeQueue',
        params: {
            result: result
        }
    };
    postData(payload);
};

self.responseExecJs = function (result) {
    let payload = {
        method: 'AtomDebug.responseExecJs',
        params: {
            result: result
        }
    };
    postData(payload);
};


self.command = {
    write(result) {
        let payload = {
            method: 'AtomDebug.commandWrite',
            params: {
                result: result
            }
        };
        postData(payload);
    }
};

eventEmitter.on('AtomDebug.initJSRuntime', function (message) {
    channelId = message.channelId;
    importScripts(message.params.url);
    self.responseInitJsFramework("1");
    setDebuggerInteract(true);
});

eventEmitter.on('AtomDebug.getConsumeQueue', function (message) {
    try {
        isCommandsDebugger && console.log('Runtime:consumeQueue', message.params.args);
        const result = ATOM_NATIVE_EXEC_COMMAND_AND_CONSUME_QUEUE_DEBUG(message.params.args);
        isCommandsDebugger && console.log('Runtime:~consumeQueue', result);
        self.responseGetConsumeQueue(result);
    } catch (e) {
        console.error(e);
        self.responseGetConsumeQueue('[]');
    }
});

eventEmitter.on('AtomDebug.changeLogLevel', function (message) {
    self.WXEnvironment.logLevel = message.params;
});

eventEmitter.on('AtomDebug.setCommandsLog', function (data) {
    isCommandsDebugger = data.params.messageText;
});

eventEmitter.on('AtomDebug.setFrameworkLog', function (data) {
    /*eslint-disable*/
    ATOM_NATIVE_EXEC_DEBUG(data.params.messageText);
    /*eslint-disable*/
});

eventEmitter.on('AtomDebug.setDebuggerInteract', function (data) {
    setDebuggerInteract(data.params.messageText);
});

eventEmitter.on('AtomDebug.importScript', function (data) {
    if (data.params.sourceUrl) {
        importScripts(data.params.sourceUrl);
    }
    else {
        new Function('', data.params.source)();
    }
    self.responseExecJs("1");
})

function dump(id) {
    postMessage({
        method: 'Runtime.dom',
        params: getRoot(id)
    })
}

function syncRequest(data) {
    let request = new XMLHttpRequest();
    request.open('POST', '/syncApi', false); // `false` makes the request synchronous
    request.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
    request.send(JSON.stringify(data));
    if (request.status === 200) {
        return JSON.parse(request.responseText);
    }
    else {
        return {
            error: request.responseText
        };
    }
}
/*eslint-enable*/