import {reactive} from "vue";
import {wx} from "~/utils/wx";
import {showFailToast} from "vant";
import { UpyunAccess } from "~/utils/upyun";
import usePool from "~/store/pool";

enum AudioPlayModes {
    None, Html, Wechat
}

export interface AudioStore {
    playing: string,
    loading: string,
    stopping: boolean,
    next?: () => void,
    mode: AudioPlayModes,
    target?: any
}

export interface AudioRecorder {
    recording: boolean,
    localId: string,
    done?: (media_id: string) => void
}

const caches = {} as any;

const store = reactive<AudioStore>({
    playing: '',
    loading: '',
    stopping: false,
    mode: AudioPlayModes.None
})

const recorder = reactive<AudioRecorder>({
    recording: false,
    localId: ''
})

const reset = () => {
    store.playing = '';
    store.loading = '';
    store.stopping = false;
    store.next = undefined;
    store.mode = AudioPlayModes.None;
    store.target = undefined;
}

const audio = new Audio()
audio.addEventListener('canplaythrough', async () => {
    if (!store.stopping) {
        store.playing = store.loading;
        store.loading = ''
        await audio.play();
    } else {
        let {next} = store;
        reset();
        if (next) next();
    }
})

audio.addEventListener('ended', () => {
    reset();
})

audio.addEventListener('error', () => {
    let {next} = store;
    reset();
    if (next) next()
})

export default function useAudio() {

    const {setRemoteCache} = usePool();

    const cache = (localId: string, serverId: string) => {
        caches[serverId] = localId;
        // cache current data to redis
        setRemoteCache(serverId + "_" + localId)
    }

    const play_by_html = async (audio_url: string) => {
        store.loading = audio_url;
        audio.src = (await UpyunAccess.getSign(audio_url)) as string;
        store.mode = AudioPlayModes.Html
        audio.load();
    }

    const wx_play_local = (localId: string) => {
        if (store.stopping) {
            reset();
            return;
        }
        store.mode = AudioPlayModes.Wechat
        store.playing = localId;
        store.loading = '';
        wx.playVoice({localId})
        wx.onVoicePlayEnd({
            complete: reset, fail: () => {
                showFailToast('音频播放失败！')
            }
        })
    }

    const play_by_wx = ({localId, serverId}: any) => {
        localId = localId || caches[serverId];
        if (localId) {
            wx_play_local(localId)
        } else if (serverId) {
            store.loading = serverId;
            wx.downloadVoice({
                serverId, isShowProgressTips: 0,
                success: ({localId}: any) => {
                    store.loading = '';
                    caches[serverId] = localId;
                    wx_play_local(localId);
                },
                fail: (err: any) => {
                    console.error('wx download voice failed...', err)
                }
            });
        }
    }

    const play_next = ({target, audio_url, serverId, localId}: any) => {
        store.target = target;
        if (audio_url) {
            play_by_html(audio_url);
        } else {
            play_by_wx({serverId, localId});
        }
    }

    const play = (data: any) => {
        if (store.playing) {
            stop(data)
        } else {
            play_next(data);
        }
    }

    const stop_html_play = () => {
        audio.pause();
        audio.currentTime = 0;
        audio.src = ''
        reset();
    }

    const stop_wx_play = (callback: () => void) => {
        wx.stopVoice({
            localId: store.playing,
            success: () => {
                reset();
                callback();
            },
            fail: (err: any) => {
                console.error("stop voice failed...", err)
            }
        })
    }

    const stop = (data?: any) => {
        store.stopping = true;
        let {audio_url, serverId, localId} = data || {};
        let next = audio_url || localId || caches[serverId];
        if (store.playing) {
            if (store.mode === AudioPlayModes.Html) {
                stop_html_play();
                if (next && next !== store.playing) {
                    play_next(data)
                }
            } else if (store.mode === AudioPlayModes.Wechat) {
                stop_wx_play(() => {
                    if (next && next !== store.playing) {
                        play_next(data);
                    }
                })
            }
        }
    }


    const upload = (localId: string): Promise<string| null> => {
        console.log('record done...', localId)
        recorder.localId = localId;
        return new Promise((resolve, reject) => {
            wx.uploadVoice({
                localId,
                success: ({serverId}: any) => {
                    cache(localId, serverId);
                    recorder.localId = '';
                    resolve(serverId);
                },
                fail: (err: any) => {
                    console.log('wx upload error...', err);
                    showFailToast('语音上传失败，请稍后重试!');
                    recorder.localId = '';
                    resolve(null)
                },
                complete: () => {
                    recorder.recording = false;
                }
            });
        })
    };

    const startRecord = async (done: (media_id: string) => void) => {
        recorder.done = done;
        if (recorder.recording) {
            await stopRecord();
            return;
        }
        console.log('start recording...')
        recorder.recording = true;
        recorder.localId = '';
        await wx.startRecord();
        wx.onVoiceRecordEnd({complete: upload});
    }

    const stopRecord = async () => {
        if (!recorder.recording) return Promise.resolve();
        return new Promise((resolve, reject) => {
            wx.stopRecord({
                success: async ({localId}: any) => {
                    let media_id = await upload(localId);
                    if (media_id && recorder.done) {
                        recorder.done(media_id);
                    }
                    resolve(media_id);
                },
                fail: (err: any) => {
                    console.error('wx stop record failed...', err);
                    resolve(null);
                }
            });
        })
        
    }


    return {store, recorder, play, stop, cache, startRecord, stopRecord}

}
