

function VideoMediaSource(element) {
    let videoElement = null;
    let codecInfo = null;

    let mediaSource = null;
    let sourceBuffer = null;

    let initSegmentData = null;

    let ctrlDelayFlag = false;
    let delay = 1;
    const DELAY = 0.5;
    let waitingCount = 0;
    let time = 0;

    let segmentWaitDecode = [];

    let firstTimeStamp = null;
    let isFirstTimeStamp = false;


    let onDurationChangeCallback = null;
    let onCanplayCallback = null;
    let startPlay = false;

    function constructor(element) {
        videoElement = element;
    }

    constructor.prototype = {
        init() {
            videoElement.controls = false;
            videoElement.autoplay = 'autoplay';
            //videoElement.preload = "auto";
            videoElement.muted = true;

            addVideoEventListener(videoElement);

            appendInitSegment();
        },

        setMediaSegment(mediaSegment) {
            appendNextMediaSegment(mediaSegment)
        },

        setFirstTimeStamp(time) {
            if(!isFirstTimeStamp) {
                console.log('set firstTimeStamp:', time)
                firstTimeStamp = time;
                isFirstTimeStamp = true;
            }
        },

        setDurationChangeCallBack(callback) {
            onDurationChangeCallback = callback;
        },

        set CodecInfo(CodecInfo) {
            codecInfo = CodecInfo;
        },

        get CodecInfo() {
            return codecInfo;
        },

        set InitSegment(data) {
            initSegmentData = data;
        },

        get InitSegment() {
            return initSegmentData;
        },

        onCanplayCallback(callback) {
            onCanplayCallback = callback;
        },

        close() {
            videoElement.pause();
            removeEventListener();
            mediaSource.removeSourceBuffer(sourceBuffer);
            mediaSource.endOfStream();
            sourceBuffer = null;
            mediaSource = null;
            videoElement = null;
        }
    }

    return new constructor(element);

    function appendInitSegment() {
        if(mediaSource == null || mediaSource.readyState === 'end') {
            mediaSource = new MediaSource();
            addMediaSourceEventListener(mediaSource);
            videoElement.src = window.URL.createObjectURL(mediaSource);
            //console.log('new MediaSource');
            return;
        }

        //console.log('appendInitSegment start');
        if(mediaSource.sourceBuffers.length === 0) {
            mediaSource.duration = 0;
            let codecs = 'video/mp4;codecs="avc1.' + codecInfo + '"';
            if(!MediaSource.isTypeSupported(codecs)) {
                //console.log('要播放视频格式 video/mp4;codecs="avc1.64002a", video/mp4;codecs="avc1.64002a"，您还需要安装一个额外的微软组件，参见 https://support.mozilla.org/kb/fix-video-audio-problems-firefox-windows')
                console.log('not support ' + codecs)
                return;
            }
            sourceBuffer = mediaSource.addSourceBuffer(codecs);
            addSourceBufferEventListener(sourceBuffer);
        }

        let initSegment = initSegmentData;
        if(initSegment == null) {
            mediaSource.endOfStream();
            console.log('no initSegmentData');
        }
        //console.log(sourceBuffer)
        sourceBuffer.appendBuffer(initSegment);
        //console.log(sourceBuffer)
        // saveAs(new File(initSegment, "test"));
        //  Savesegments.set(initSegment, 0);
        //  segmentsLength += initSegment.length;
        //  segmentsNum --;
        console.log('appendInitSegment end')
        checkDelay();
    }

    function appendNextMediaSegment(mediaData) {


        if(sourceBuffer == null) {
            segmentWaitDecode.push(mediaData);
            return;
        }
        //console.log(mediaSource.readyState, mediaSource.readyState,sourceBuffer.updating)
        if(mediaSource.readyState === 'closed' || mediaSource.readyState === "ended") {
            console.log('mediaSource closed or ended')
            return;
        }

        if(onDurationChangeCallback) {
            //90000为采样率，先写死
            let rtpTimestamp = parseInt((videoElement.currentTime.toFixed(2) * 90000).toFixed(0)) + firstTimeStamp + 3600;//
            //console.log('callback time: ', rtpTimestamp)
            //console.log('sourceBuffer: ', sourceBuffer.timestampOffset)
            onDurationChangeCallback(rtpTimestamp);
        }

        //console.count('一帧');

        //try {
        if(segmentWaitDecode.length) {
            segmentWaitDecode.push(mediaData);
            //console.log(segmentWaitDecode)
        }else {
            if(!sourceBuffer.updating) {
                sourceBuffer.appendBuffer(mediaData);
            } else {
                segmentWaitDecode.push(mediaData);
            }
        }
        //}catch (e){
        //    console.log('appendNextMediaSegment Error')
        //}

        if(sourceBuffer && sourceBuffer.buffered && sourceBuffer.buffered.length &&  sourceBuffer.buffered.end(0) > DELAY) {
            if(!startPlay) {
                videoElement.play();
                console.warn('playbakrate: ', videoElement.playbackRate)
            }
            startPlay = true;
        } else {
            if(!startPlay) {
                videoElement.pause();
            }
        }
        //console.log(sourceBuffer)
    }

    /**
     * Video事件
     * @param videoElement video对象
     */
    function addVideoEventListener(videoElement) {
        videoElement.addEventListener('loadstart', onloadstart);

        videoElement.addEventListener('waiting', onWaiting);

        videoElement.addEventListener('durationchange', onDurationChange);

        videoElement.addEventListener('timeupdate', timeupdate);

        videoElement.addEventListener('canplay', oncanplay);

        videoElement.addEventListener('canplaythrough', oncanplaythrough);

        videoElement.addEventListener('error', onVideoError);

        document.addEventListener('visibilitychange', onVisibilityChange);
    }

    function onVisibilityChange(e) {
        if(document.visibilityState === 'visible') {
            ctrlDelayFlag = true;
            console.log(videoElement);
            checkDelay();
            videoElement.play();
        } else {
            ctrlDelayFlag = false;
            videoElement.pause();
        }
        console.warn('visibilityState: ', document.visibilityState)
    }

    function onloadstart() {
        console.log('loadstart');
    }

    function onDurationChange() {
        //console.log('durationchange');
        if (mediaSource === null) {
            return;
        }

        if(sourceBuffer && sourceBuffer.buffered && sourceBuffer.buffered.length > 0) {
            checkBuffer();
        }
        //console.log('currentTime：', videoElement.currentTime);
        // if(onDurationChangeCallback) {
        //     //90000为采样率，先写死
        //     let rtpTimestamp = videoElement.currentTime * 90000 + firstTimeStamp ;
        //     //console.log('callback time: ', rtpTimestamp)
        //     onDurationChangeCallback(rtpTimestamp);
        // }

        //try {

        //}catch(e) {
        //    console.log('sourceBuffer has been moved')
        //}

    }

    function checkDelay() {
        if(sourceBuffer && sourceBuffer.buffered && sourceBuffer.buffered.length > 0) {
            //console.log('end: ',sourceBuffer.buffered.end(0))
            if(ctrlDelayFlag) {
                let startTime = sourceBuffer.buffered.start(0);
                let endTime = sourceBuffer.buffered.end(0);
                let diffTime = (videoElement.currentTime === 0 ? endTime - startTime: endTime - videoElement.currentTime).toFixed(2);
                if(diffTime >= delay + 0.1) {
                    if(sourceBuffer.updating) {
                        return;
                    }
                    let tempCurrntTime = endTime - delay;
                    console.log('跳秒前', videoElement.currentTime)
                    videoElement.currentTime = tempCurrntTime.toFixed(3);
                    console.log('跳秒后', videoElement.currentTime, sourceBuffer.buffered.end(0), videoElement.duration)
                    //ctrlDelayFlag = false;
                } else if((diffTime < DELAY + 0.1 ) && diffTime >= DELAY) {
                    //console.log('playbackRate:', 1, diffTime)
                    videoElement.playbackRate = 1;
                }
                else if(diffTime < DELAY) {
                    videoElement.playbackRate = 0.9;
                }else {
                    //console.log('playbackRate:', 1.1, diffTime)
                    videoElement.playbackRate = 1.1;
                }
            }
        }
        window.requestAnimationFrame(checkDelay);
    }

    function timeupdate() {
        // console.log('******timeupdate******');
        // console.log(videoElement.currentTime);
        // console.log('******timeupdate end******')
    }

    function oncanplay() {
        // if(isFirstTimeStamp && (firstTimeStamp == null)) {
        //     //firstTimeStamp =
        //     isFirstTimeStamp = false;
        // }

        onCanplayCallback && onCanplayCallback(videoElement);
        console.log('canplay');
    }

    function oncanplaythrough() {
        if(document.visibilityState === 'visible' && startPlay){ctrlDelayFlag = true};
        console.log('canplaythrough');
    }

    function onVideoError() {
        console.error('error');
        //console.log(e)
        console.error(videoElement.currentTime);
        console.error("Error " + videoElement.error.code + "; details: " + videoElement.error.message);
    }


    /**
     * MediaSource事件
     * @param mediaSource
     */
    function addMediaSourceEventListener(mediaSource) {
        mediaSource.addEventListener('sourceopen', onSourceOpen);

        mediaSource.addEventListener('error', onMediaSourceError);
    }

    function onSourceOpen() {
        console.log('OnsourceOpen');
        appendInitSegment(); //此处重新调用一次，是为了建立sourceBuffer
    }

    function onMediaSourceError() {
        console.log('mediaSource error');
        console.log(videoElement.currentTime)
    }

    /**
     * sourceBuffer事件
     */
    function addSourceBufferEventListener(sourceBuffer) {
        sourceBuffer.addEventListener('error', onSourceBufferError);

        sourceBuffer.addEventListener('update', onUpdate);
    }

    function onSourceBufferError() {
        console.log('sourceBuffer Error');
        console.log(videoElement.currentTime)
    }

    function onUpdate() {
        //console.log('sourceBuffer update');
        if(segmentWaitDecode.length > 0) {
            if(!sourceBuffer.updating) {
                sourceBuffer.appendBuffer(segmentWaitDecode[0]);

                //console.log('segmentWaitDecode:  ' + segmentWaitDecode.length)
                segmentWaitDecode.shift();
            }
        }
        //console.log(e)
    }

    function checkBuffer() {
        let minute = 20;
        let bufferTime = 10;
        let startTime = sourceBuffer.buffered.start(0);
        let endTime = sourceBuffer.buffered.end(0);
        //console.log(endTime- videoElement.currentTime)
        if (!sourceBuffer.updating && (endTime - startTime > minute)) {
            sourceBuffer.remove(startTime, endTime - bufferTime);
            console.log('remove buffer: ', startTime, ' - ', (endTime - bufferTime))
        }else if(sourceBuffer.updating && (endTime - startTime > minute)) {
            console.log('clear buffer failed!')
        }
    }

    function onWaiting() {
        console.log('waiting....');
        ctrlDelayFlag = false;
        // if(delay < 0.7) {
        //     if(waitingCount === 0) {
        //         time = Date.now();
        //         waitingCount++;
        //     }else {
        //         if((Date.now() - time) <= 5000) {
        //             waitingCount ++;
        //             if(waitingCount >= 5) {
        //                 delay += 0.1;
        //                 console.log('delay: ', delay);
        //                 time = Date.now();
        //                 waitingCount = 0;
        //             }
        //         } else {
        //             waitingCount = 1;
        //             time = Date.now();
        //         }
        //     }
        // }
    }

    function removeEventListener() {
        document.removeEventListener('visibilitychange', onVisibilityChange);
        videoElement.removeEventListener('loadstart', onloadstart);
        videoElement.removeEventListener('waiting', onWaiting);
        videoElement.removeEventListener('durationchange', onDurationChange);
        videoElement.removeEventListener('timeupdate', timeupdate);
        videoElement.removeEventListener('canplay', oncanplay);
        videoElement.removeEventListener('canplaythrough', oncanplaythrough);
        videoElement.removeEventListener('error', onVideoError);

        mediaSource.removeEventListener('sourceopen', onSourceOpen);
        mediaSource.removeEventListener('error', onMediaSourceError);

        sourceBuffer.removeEventListener('error', onSourceBufferError);
        sourceBuffer.removeEventListener('update', onUpdate);
    }

}



export default VideoMediaSource;
