/**
 * 音频相关接口、类
 */
import { callNativeSync, emptyFn, callNative } from './util';

/**
 * Audio类
 * 实例属性的`getter`和`setter`及接口调用都通过`同步方式`与Native通信
 * 事件的回调保存在`this.__eventListeners`对象下对应的各个key中
 * 通过`this.__id`来确认Native端唯一的一个`Audio`实例对象
 *
 * @class Audio
 */
class Audio {
    constructor(id) {
        Object.defineProperties(this, {
            __eventListeners: {
                value: Object.defineProperties({}, {
                    onCanplay: { value: [] },
                    onPlay: { value: [] },
                    onPause: { value: [] },
                    onStop: { value: [] },
                    onEnded: { value: [] },
                    onTimeUpdate: { value: [] },
                    onError: { value: [] },
                    onWaiting: { value: [] },
                    onSeeking: { value: [] },
                    onSeeked: { value: [] },
                }),
                writable: false,
                enumerable: false,
                configurable: false
            },
            __id: {
                value: id,
                writable: false,
                enumerable: false,
                configurable: false
            },
            src: {
                get() {
                    return callNativeSync('audio.getSrc', {
                        id: this.__id
                    }).data.value;
                },
                set(value) {
                    callNativeSync('audio.setSrc', {
                        id: this.__id,
                        value: value
                    });

                    return value;
                },
                enumerable: true,
            },
            startTime: {
                get() {
                    return callNativeSync('audio.getStartTime', {
                        id: this.__id
                    }).data.value;
                },
                set(value) {
                    callNativeSync('audio.setStartTime', {
                        id: this.__id,
                        value: value
                    });

                    return value;
                },
                enumerable: true,
            },
            autoplay: {
                get() {
                    return callNativeSync('audio.getAutoplay', {
                        id: this.__id
                    }).data.value;
                },
                set(value) {
                    callNativeSync('audio.setAutoplay', {
                        id: this.__id,
                        value: value
                    });

                    return value;
                },
                enumerable: true,
            },
            loop: {
                get() {
                    return callNativeSync('audio.getLoop', {
                        id: this.__id
                    }).data.value;
                },
                set(value) {
                    callNativeSync('audio.setLoop', {
                        id: this.__id,
                        value: value
                    });

                    return value;
                },
                enumerable: true,
            },
            obeyMuteSwitch: {
                get() {
                    return callNativeSync('audio.getObeyMuteSwitch', {
                        id: this.__id
                    }).data.value;
                },
                set(value) {
                    callNativeSync('audio.setObeyMuteSwitch', {
                        id: this.__id,
                        value: value
                    });

                    return value;
                },
                enumerable: true,
            },
            volume: {
                get() {
                    return callNativeSync('audio.getVolume', {
                        id: this.__id
                    }).data.value;
                },
                set(value) {
                    callNativeSync('audio.setVolume', {
                        id: this.__id,
                        value: value
                    });

                    return value;
                },
                enumerable: true,
            },
            duration: {
                get() {
                    return callNativeSync('audio.getDuration', {
                        id: this.__id
                    }).data.value;
                },
                enumerable: true
            },
            currentTime: {
                get() {
                    return callNativeSync('audio.getCurrentTime', {
                        id: this.__id
                    }).data.value;
                },
                enumerable: true,
            },
            paused: {
                get() {
                    return callNativeSync('audio.getPaused', {
                        id: this.__id
                    }).data.value;
                },
                enumerable: true,
            },
            buffered: {
                get() {
                    return callNativeSync('audio.getBuffered', {
                        id: this.__id
                    }).data.value;
                },
                enumerable: true,
            }
        });

        Audio.audios[id] = this;
    }

    play() {
        callNativeSync('audio.play', { id: this.__id });
    }

    pause() {
        callNativeSync('audio.pause', { id: this.__id });
    }

    stop() {
        callNativeSync('audio.stop', { id: this.__id });
    }

    seek(seek) {
        callNativeSync('audio.seek', { id: this.__id, seek }, { seek: 'Number' });
    }

    destroy() {
        callNativeSync('audio.destroy', { id: this.__id });
    }

    onCanplay(callback) {
        this.__eventListeners.onCanplay.push(callback);
    }
    offCanplay(callback) {
        const index = this.__eventListeners.onCanplay.indexOf(callback);
        if (index >= 0) {
            this.__eventListeners.onCanplay.splice(index, 1);
        }
    }

    onPlay(callback) {
        this.__eventListeners.onPlay.push(callback);
    }
    offPlay(callback) {
        const index = this.__eventListeners.onPlay.indexOf(callback);
        if (index >= 0) {
            this.__eventListeners.onPlay.splice(index, 1);
        }
    }

    onPause(callback) {
        this.__eventListeners.onPause.push(callback);
    }
    offPause(callback) {
        const index = this.__eventListeners.onPause.indexOf(callback);
        if (index >= 0) {
            this.__eventListeners.onPause.splice(index, 1);
        }
    }

    onStop(callback) {
        this.__eventListeners.onStop.push(callback);
    }
    offStop(callback) {
        const index = this.__eventListeners.onStop.indexOf(callback);
        if (index >= 0) {
            this.__eventListeners.onStop.splice(index, 1);
        }
    }

    onEnded(callback) {
        this.__eventListeners.onEnded.push(callback);
    }
    offEnded(callback) {
        const index = this.__eventListeners.onEnded.indexOf(callback);
        if (index >= 0) {
            this.__eventListeners.onEnded.splice(index, 1);
        }
    }

    onTimeUpdate(callback) {
        this.__eventListeners.onTimeUpdate.push(callback);
    }
    offTimeUpdate(callback) {
        const index = this.__eventListeners.onTimeUpdate.indexOf(callback);
        if (index >= 0) {
            this.__eventListeners.onTimeUpdate.splice(index, 1);
        }
    }

    onError(callback) {
        this.__eventListeners.onError.push(callback);
    }
    offError(callback) {
        const index = this.__eventListeners.onError.indexOf(callback);
        if (index >= 0) {
            this.__eventListeners.onError.splice(index, 1);
        }
    }

    onWaiting(callback) {
        this.__eventListeners.onWaiting.push(callback);
    }
    offWaiting(callback) {
        const index = this.__eventListeners.onWaiting.indexOf(callback);
        if (index >= 0) {
            this.__eventListeners.onWaiting.splice(index, 1);
        }
    }

    onSeeking(callback) {
        this.__eventListeners.onSeeking.push(callback);
    }
    offSeeking(callback) {
        const index = this.__eventListeners.onSeeking.indexOf(callback);
        if (index >= 0) {
            this.__eventListeners.onSeeking.splice(index, 1);
        }
    }

    onSeeked(callback) {
        this.__eventListeners.onSeeked.push(callback);
    }
    offSeeked(callback) {
        const index = this.__eventListeners.onSeeked.indexOf(callback);
        if (index >= 0) {
            this.__eventListeners.onSeeked.splice(index, 1);
        }
    }
}

// 保存所有audio实例，key是`this.__id`
Audio.audios = {};

export {
    Audio
};

export default {
    /**
     * 创建内部 audio 上下文 InnerAudioContext 对象。
     *
     * @returns {Audio}
     */
    createInnerAudioContext() {
        const id = callNativeSync('createInnerAudioContext').data.id;

        return new Audio(id);
    },
    /**
     * 设置 InnerAudioContext 的播放选项。设置之后对当前小程序全局生效。
     *
     * @param {Object} options
     * @param {Boolean} [options.mixWithOther = true] 是否与其他音频混播，设置为 true 之后，不会终止其他应用或App内的音乐
     * @param {Boolean} [options.obeyMuteSwitch = true] （仅在 iOS 生效）是否遵循静音开关，设置为 false 之后，即使是在静音模式下，也能播放声音
     * @param {Function} [options.success = emptyFn] 成功回调
     * @param {Function} [options.fail = emptyFn] 失败回调
     */
    setInnerAudioOption({
        mixWithOther = true,
        obeyMuteSwitch = true,
        success = emptyFn,
        fail = emptyFn,
        complete = emptyFn
    } = {}) {
        callNative('setInnerAudioOption', { mixWithOther: !!mixWithOther, obeyMuteSwitch: !!obeyMuteSwitch, success, fail, complete });
    },
    /**
     * 获取当前支持的音频输入源
     *
     * @param {Object} [options = {}]
     */
    getAvailableAudioSources(options = {}) {
        callNative('getAvailableAudioSources', options);
    }
};
