/**
 * 直播播放器
 * @param {string} elementId 元素Id
 * @param {string} url 直播地址
 */
class LivePlayer {
    constructor(elementId, url) {
        this.elementId = elementId;
        this.url = url;
        this._init();
    }

    /**
     * 全局初始化
     * @returns {Promise<void>}
     */
    static init() {
        return new Promise((resolve, _) => {
            NodePlayer.load(() => {
                //v0.5.70版之后,在Android手机端推荐使用以下音频引擎
                if (/(Android)/i.test(navigator.userAgent)) {
                    NodePlayer.activeAudioEngine(true);
                }
                resolve();
            });
        });
    }

    /**
     * 播放
     * @param {bool} keepRetry 保持重试
     */
    play(keepRetry = true) {
        this._keepRetry = keepRetry;
        this._nplayer.start(this.url);
    }
    /**
     * 停止
     */
    stop() {
        this._keepRetry = false; //关闭重试
        this._nplayer.stop();
    }

    /**
     * 声音
     */
    enableAudio(keepEnableAudio = true) {
        this._nplayer.setVolume(keepEnableAudio ? 1 : 0);
    }

    /**
     * 设置视图尺寸
     * @param {number} width
     * @param {number} height
     */
    setViewSize(width, height) {
        this._nplayer.resizeView(width, height);
    }

    releasePlayer() {
        this._nplayer.release();
    }

    _init() {
        this._retryCount = 0;
        this._fpsEmptyCount = 0;
        const player = new NodePlayer();
        this._nplayer = player;
        let hasPlayed = false;
        let gotVideoInfo = false;

        // 开启屏幕常亮
        player.setKeepScreenOn();
        // 绑定dom
        player.setView(this.elementId);
        // 设置最大缓冲时长，单位毫秒
        player.setBufferTime(5000);
        // 设置超时时长, 单位秒；回调timeout事件
        player.setTimeout(10);
        // 缩放模式，0 fill，1 contain，2 cover
        player.setScaleMode(1);
        // 禁用音频
        // player.enableAudio(false);

        // 手动定时器，用于检测是否有视频流
        setTimeout(() => {
            if (!gotVideoInfo) {
                this.onTimeout && this.onTimeout();
                this._tryReConnect();
            }
        }, 15000);

        player.on('videoInfo', (w, h, codec) => {
            gotVideoInfo = true;
            if (!!this.onInfo) {
                this.onInfo({ width: w, height: h });
            }
        });
        player.on('audioInfo', (r, c, codec) => {
            if (!!this.onAudioInfo) {
                this.onAudioInfo({ r: r, c: c });
            }
        });
        player.on('videoFrame', (pts) => {
            /// 每一帧执行一次视频处理
            this.onFrame && this.onFrame();
        });
        player.on('timeout', () => {
            this.onTimeout && this.onTimeout();
        });
        player.on('start', () => {
            hasPlayed = true;
            this.onPlay && this.onPlay();
        });
        player.on('stop', () => {
            this.onStop && this.onStop();
            this._onStop();
        });
        player.on('buffer', (state) => {
            this.onBuffer && this.onBuffer(state);
        });
        player.on('error', (error) => {
            // {code:404,msg:"not found"}
            this.onError && this.onError(error);
        });
        player.on('stats', (stats) => {
            if (stats.abps === 0 && stats.fps === 0 && stats.vbps === 0) {
                console.log(
                    `stats - abps: ${stats.abps}, fps: ${stats.fps}, vbps: ${stats.vbps}.`,
                );
                if (!hasPlayed) return;

                this._fpsEmptyCount++;
                if (this._fpsEmptyCount > 50) {
                    // nodeplay连续5次拉不到流
                    this._tryReConnect();
                }
            }
        });
    }

    _onStop() {
        const retry = this._keepRetry;
        if (retry === true) {
            if (this._retryCount > 12) {
                this._tryReConnect();
            } else {
                setTimeout(() => {
                    this._retryCount += 1;
                    this.play(retry);
                }, 800);
            }
        }
    }

    /// 尝试断线后重连
    async _tryReConnect() {
        this._fpsEmptyCount = 0;
        this._retryCount = 0;
        this.releasePlayer();
        if (!!this.onBeforeReconnect) {
            let result = await this.onBeforeReconnect();
            // 即使超声机下线了也要继续尝试重连，故把下面这段注释了
            // if (!result) {
            //   // 放弃重连
            //   return;
            // }
        }
        this._init();
        this.play(true);
    }
}
