import { EventEmitter } from 'events'
const playType = {
    REALPLAY: 'realplay',
    PLAYBACK: 'playback',
    TALK: 'talk'
}

class StreamWebsocket {
    private _ws:any = null
    private _headBuffer:any = null
    private _lastCmd:any = null
    private _receivedSteamHead:boolean = false
    _requestData={
        playUrl:'',
        playType:'playback',
        startTime:0,
        endTime:0,
    }

    emitter: any
    constructor(url:string, playType = 'playback' ) {
        this.emitter = new EventEmitter()
        this._requestData.playUrl = url
        this._requestData.playType = playType
    }

    on(event:any, listener:any) {
        this.emitter.addListener(event, listener);
    }

    off(event:any, listener:any) {
        this.emitter.removeListener(event, listener);
    }

    sendArrayBuffer(arrBuf:any) {
        this._ws.send(arrBuf)
    }

    open(url?:string) {
        return new Promise((resolve, reject) => {
            this.emitter.on(`cmd.${this._requestData.playType}`, (code:any, mediaInfo:any) => {
                if (code === 0) {
                    resolve({
                        code,
                        mediaInfo,
                        playType: this._requestData.playType,
                        head: this._headBuffer
                    })
                } else {
                    // resolve({})
                    reject(code)
                }
            })
            const _url = url || this._requestData.playUrl
            this._ws = new WebSocket(_url)
            this._ws.binaryType = 'arraybuffer'
            this._ws.onopen = (val:any) => {
                // console.log('onopen',val)
            }
            this._ws.onerror = (err:any) => {
                // console.log('onerror',err)
                // this._bError = true
            }
            this._ws.onclose = () => {
                // console.log('close')
                // if (this._receivedSteamHead) {
                //     this.emitter.emit('stream.interrupt', 'codes.ERR_INTERRUPT')
                // }
                this.emitter.emit(`cmd.${this._requestData.playType}`, '0x-000000')
            }
            this._ws.onmessage = (msg:any) => {
                let { data } = msg
                if (data instanceof ArrayBuffer) {
                    this._handleStream(data)
                } else if (typeof data === 'string') {
                    this._handleInteract(data)
                }
            }
        })
    }

    /**
     * 码流处理
     * @param {*} bufData
     * @returns
     */
    _handleStream(bufData:any) {
        if (!this._receivedSteamHead) {
            this._headBuffer = bufData
            this._receivedSteamHead = true
            let isHead = true
            if (this.emitter.eventNames().includes(`cmd.${this._requestData.playType}`)) {
                this.emitter.emit(`cmd.${this._requestData.playType}`, 0)
            }
            this.emitter.emit('stream.input', bufData, isHead)
        } else {
            this.emitter.emit('stream.input', bufData)
        }
    }

    /**
     * 交互信息处理
     * @param {*} strData
     */
    _handleInteract(strData:any) {
        let jsonData = JSON.parse(strData)
        if (!this._lastCmd) {   // 开流
            let { errorCode, errorMsg } = jsonData
            if (parseInt(errorCode) === 0) {    // 安全认证成功，与服务端建立连接
                if (this._requestData.playType === playType.TALK) {
                    this.emitter.emit(`cmd.${this._requestData.playType}`, errorCode, jsonData.audioInfo)
                } else {
                    this.emitter.emit(`cmd.${this._requestData.playType}`, errorCode)
                }
            } else {
                let errorCodeHex = '0x0' + errorCode.toString(16)
                this.emitter.emit(`cmd.${this._requestData.playType}`, errorCodeHex, errorMsg)
            }
            return
        }

        if (jsonData.hasOwnProperty('errorCode')) { // 交互消息
            let { errorCode, errorMsg } = jsonData
            if (parseInt(errorCode) === 0) {
                this.emitter.emit(`cmd.${this._lastCmd.cmd}`, parseInt(errorCode))
            } else {
                let errorCodeHex = '0x0' + errorCode.toString(16)
                this.emitter.emit(`cmd.${this._lastCmd.cmd}`, errorCodeHex, errorMsg)
            }
        } else {    // 服务端主动消息
            if (!jsonData.hasOwnProperty('cmd')) {
                let extra:any = {
                    url: this._requestData.playUrl
                }
                let cmd = this._requestData.playType
                if (this._requestData.playType === playType.PLAYBACK) {
                    extra.startTime = this._requestData.startTime
                    extra.endTime = this._requestData.endTime
                }
                this.sendCmd(cmd, extra).catch((err) => {
                    console.error(err)
                })
            } else {
                let { cmd } = jsonData
                if (cmd === 'end') {
                    this.emitter.emit('stream.end')
                    this.close()
                }
                else if (cmd === 'newStreamFlag') {}
            }
        }
    }

    sendCmd(cmd, extra = {}) {
        return new Promise((resolve, reject) => {
            if (!this._ws || this._ws.readyState !== WebSocket.OPEN) {
                return reject('意外的状态')
            }
            // 设置消息发送监听
            this.emitter.once(`cmd.${cmd}`, (code) => {
                if (code === 0) {
                    resolve('codes.OK')
                } else {
                    reject(code)
                }
            })
            // 发送消息
            let cmdBody = {
                cmd,
                ...extra,
                sequence: !this._lastCmd ? 0 : this._lastCmd.sequence + 1,
            }

            this._ws.send(JSON.stringify(cmdBody))
            this._lastCmd = cmdBody
        })
    }

    destroy() {
        this.close()
        if(this.emitter){
            this.emitter.removeAllListeners()
            this.emitter = null;
        }
    }

    close() {
        if (!this._ws)
            return

        let ws = this._ws
        ws.close(1000)
        ws.onmessage = null
        ws.onclose = null
        ws.onerror = null
        ws.onopen = null
        this._ws = null
        this._receivedSteamHead = false
        this._lastCmd = null
    }
}

export default StreamWebsocket
