const inputManager = cc.internal.inputManager;
const renderer = cc.renderer;
const game = cc.game;
const dynamicAtlasManager = cc.dynamicAtlasManager;

let originRun = game.run;
Object.assign(game, {
    _banRunningMainLoop: __globalAdapter.isSubContext,
    _firstSceneLaunched: false,

    run () {
        cc.director.once(cc.Director.EVENT_AFTER_SCENE_LAUNCH, () => {
            this._firstSceneLaunched = true;
        });
        originRun.apply(this, arguments);
    },
    
    setFrameRate (frameRate) {
        this.config.frameRate = frameRate;
        if (__globalAdapter.setPreferredFramesPerSecond) {
            __globalAdapter.setPreferredFramesPerSecond(frameRate);
        }
        else {
            if (this._intervalId) {
                window.cancelAnimFrame(this._intervalId);
            }
            this._intervalId = 0;
            this._paused = true;
            this._setAnimFrame();
            this._runMainLoop();
        }
    },

    _runMainLoop () {
        if (this._banRunningMainLoop) {
            return;
        }
        var self = this, callback, config = self.config,
            director = cc.director,
            skip = true, frameRate = config.frameRate;

        cc.debug.setDisplayStats(config.showFPS);

        callback = function () {
            if (!self._paused) {
                self._intervalId = window.requestAnimFrame(callback);
                if (frameRate === 30  && !__globalAdapter.setPreferredFramesPerSecond) {
                    skip = !skip;
                    if (skip) {
                        return;
                    }
                }
                director.mainLoop();
            }
        };

        self._intervalId = window.requestAnimFrame(callback);
        self._paused = false;
    },

    _initRenderer () {
        // Avoid setup to be called twice.
        if (this._rendererInitialized) return;

        // frame and container are useless on minigame platform
        let sys = cc.sys;
        if (sys.platform === sys.TAOBAO || sys.platform === sys.TAOBAO_MINIGAME) {
            this.frame = this.container = window.document.createElement("DIV");
        } else {
            this.frame = this.container = document.createElement("DIV");
        }

        let localCanvas;
        if (__globalAdapter.isSubContext) {
            localCanvas = window.sharedCanvas || __globalAdapter.getSharedCanvas();
        }
        else if (sys.platform === sys.TAOBAO || sys.platform === sys.TAOBAO_MINIGAME) {
            localCanvas = window.canvas;
        }
        else {
            localCanvas = canvas;
        }
        this.canvas = localCanvas;

        this._determineRenderType();
        // WebGL context created successfully
        if (this.renderType === this.RENDER_TYPE_WEBGL) {
            var opts = {
                'stencil': true,
                // MSAA is causing serious performance dropdown on some browsers.
                'antialias': cc.macro.ENABLE_WEBGL_ANTIALIAS,
                'alpha': cc.macro.ENABLE_TRANSPARENT_CANVAS,
                'preserveDrawingBuffer': false,
            };
            renderer.initWebGL(localCanvas, opts);
            this._renderContext = renderer.device._gl;

            // Enable dynamic atlas manager by default
            if (!cc.macro.CLEANUP_IMAGE_CACHE && dynamicAtlasManager) {
                dynamicAtlasManager.enabled = true;
            }
        }
        if (!this._renderContext) {
            this.renderType = this.RENDER_TYPE_CANVAS;
            // Could be ignored by module settings
            renderer.initCanvas(localCanvas);
            this._renderContext = renderer.device._ctx;
        }

        this._rendererInitialized = true;
    },

    _initEvents () {
        let sys = cc.sys;
        // register system events
        if (this.config.registerSystemEvent) {
            inputManager.registerSystemEvent(this.canvas);
        }

        var hidden = false;

        function onHidden() {
            if (!hidden) {
                hidden = true;
                game.emit(game.EVENT_HIDE);
            }
        }

        function onShown(res) {
            if (hidden) {
                hidden = false;
                if (game.renderType === game.RENDER_TYPE_WEBGL) {
                    game._renderContext.finish();
                }                
                game.emit(game.EVENT_SHOW, res);
            }
        }
        
        // NOTE: onAudioInterruptionEnd and onAudioInterruptionBegin on ByteDance platform is not designed to behave the same as the ones on WeChat platform,
        // the callback is invoked on game show or hide on ByteDance platform, while is not invoked on WeChat platform.
        // See the docs on WeChat: https://developers.weixin.qq.com/minigame/dev/api/base/app/app-event/wx.onAudioInterruptionBegin.html
        if (sys.platform !== sys.BYTEDANCE_GAME) {
            __globalAdapter.onAudioInterruptionEnd && __globalAdapter.onAudioInterruptionEnd(function () {
                if (cc.audioEngine) cc.audioEngine._restore();
                
            });
            __globalAdapter.onAudioInterruptionBegin && __globalAdapter.onAudioInterruptionBegin(function () {
                if (cc.audioEngine) cc.audioEngine._break();
            });
        }

        // Maybe not support in open data context
        __globalAdapter.onShow && __globalAdapter.onShow(onShown);
        __globalAdapter.onHide && __globalAdapter.onHide(onHidden);

        this.on(game.EVENT_HIDE, function () {
            game.pause();
        });
        this.on(game.EVENT_SHOW, function () {
            game.resume();
        });
    },

    end () { },  // mini game platform not support this api
});