import { AssetManager, assetManager, AudioClip, AudioSource} from "cc";
import { constants } from "../data/constants";
import settingData from "../data/settingData";

/**音乐播放数据结构*/
export interface IAudioData {
    clip: AudioClip;//音乐片段
    audioSource: AudioSource;//音乐具柄
    path: string //音乐名称路径
    playStatus: boolean //播放状态
    totalTime: number;//音乐总长度时间
    time_id: number;//定时器句柄
    t: number;//统计记时
}

class audioManager {
    private static instance: audioManager = null;
    //缓存的音乐片段和音乐具柄一体 是为了 同时播放多个攻击音效
    private cachedAudioArr: Array<IAudioData> = [];
    private bundleAudios: AssetManager.Bundle = null;

    //单例
    public static ins() {
        if (!this.instance) {
            this.instance = new audioManager();
        }
        return this.instance;
    }

    /**
     * 预加载音乐
     */
    public async initialize(): Promise<void> {
        this.bundleAudios = await new Promise((resolve: Function, reject: Function) => {
            assetManager.loadBundle('audios', (err: Error, bundle: AssetManager.Bundle) => {
                if (err) {
                    reject(err);
                } else {
                    resolve(bundle);
                }
            });
        });
        for (let path of Object.values(constants.audios)) {
            if(path == "") continue;
            let audioClip: AudioClip = await new Promise((resolve: Function, reject: Function) => {
                this.bundleAudios.load(path, AudioClip, (err: Error, clip: AudioClip) => {
                    if (err) {
                        reject(err);
                    } else {
                        resolve(clip);
                    }
                });
            });
            this.cachedAudioArr.push({
                clip: audioClip, 
                audioSource: null, 
                path: path ,
                playStatus: false,
                totalTime: audioClip.getDuration(),
                time_id: -1,
                t: 0
            });
        }
        window["youxi"] = {
            SoundManager: {
                pauseAll: () => {
                    settingData.data.bg_music_status = false;
                    settingData.data.sound_status = false;
                    settingData.saveToCache();
                    if(settingData.data.bg_music_status){
                       this.play(constants.audios.bg_music,true);
                    }else{
                       this.stop(constants.audios.bg_music);
                    }
                },
                resumeAll: () => {
                    settingData.data.bg_music_status = true;
                    settingData.data.sound_status = true;
                    settingData.saveToCache();
                }
            },
            TargetedAds: {
                open: () => {
                },
                clos: () => {
                }
            },
            Fps: {
                setfps: (value) => {
                }
            }
        };
    }

    /**
     * 播放音效 不会两个相同的音乐重复播放 可以停止
     * @param path 播放音乐的路径
     * @param loop 是否循环播放
     * @param s 如果为-1则最大音量立即播放 如果为其他则慢慢音量递增起来播放
     * @returns 
     */
    private bgVolumeMax: number = 0.8;
    public play(path: string,loop: boolean = false,s: number = -1): void {
        if(!settingData.data.bg_music_status)return;
        const fun = (audio:IAudioData)=>{
            if(audio.audioSource == null){
               audio.audioSource = this.audioSourceLoop(loop);
            }
            if(audio.playStatus)return;
            audio.audioSource.clip = a.clip;
            if(audio.time_id){
                clearInterval(audio.time_id);
                if(audio.audioSource.playing){
                   audio.audioSource.pause();
                }
            }
            audio.audioSource.play();
            if(s == -1){
                audio.audioSource.volume = this.bgVolumeMax;
            }else{
                audio.t = 0;
                audio.audioSource.volume = 0;
                let interval: number = ((1 / s) / 10);
                audio.time_id = setInterval(()=>{
                    audio.t += interval;
                    let volume: number = audio.t / s;
                    if(volume >= this.bgVolumeMax){
                        clearInterval(audio.time_id);
                    }else{
                        audio.audioSource.volume = volume;
                    }
                },interval * 1000);
            }
            audio.playStatus = true;
        }
        let a: IAudioData = this.cachedAudioArr.find(e =>e.path == path);
        if(a){
            fun(a);
        }else{
            this.bundleAudios.load(path, AudioClip, (err, clip)=>{
                if (err) {
                    console.warn(err);
                }else{
                    let data: IAudioData = {
                        path: path,
                        clip: clip, 
                        audioSource: null, 
                        playStatus: false,
                        totalTime: clip.getDuration(),
                        time_id: -1,
                        t: 0
                    };
                    fun(data);
                }
            }); 
        }
    }

    /**
     * 单次播放一次的音效 可以停止
     * @param path 音乐路径
     * @param overlap 是否可以重复两个同一个音效连续播放
     * @returns 
     */
    public playOneShot(path: string,overlap: boolean = true): void {
        if(!settingData.data.sound_status)return;
        const fun = (audio:IAudioData)=>{
            if(overlap || !audio.playStatus){
                if(audio.audioSource == null){
                   audio.audioSource = this.audioSourceLoop(false);
                }
                audio.audioSource.clip = audio.clip;
                audio.audioSource.play();
                audio.audioSource.volume = 1;
                audio.playStatus = true;
            }
        }
        let a: IAudioData = this.cachedAudioArr.find(e =>e.path == path);
        if(a){
           fun(a);
        }else{
            this.bundleAudios.load(path, AudioClip, (err, clip)=>{
                if (err) {
                    console.warn(err);
                }else{
                    let data: IAudioData = {
                        path: path,
                        clip: clip, 
                        audioSource: null, 
                        playStatus: false,
                        totalTime: clip.getDuration(),
                        time_id: -1,
                        t: 0
                    };
                    this.cachedAudioArr.push(data);
                    fun(data);
                }
            }); 
        }
    }

    /**
     * 停止播放音效
     * @param path 音效路径名称
     * @param s 为-1立即停止播放 非-1则是慢慢的声音越来越小的停止播放
     * @returns 
     */
    public stop(path: string,s: number = -1): void {
        let audio: IAudioData = this.cachedAudioArr.find(e =>e.path == path);
        if(audio){
            if(!audio.audioSource)return;
            if(!audio.audioSource.playing)return;
            if(audio.time_id){
               clearInterval(audio.time_id);
            }
            let audioSource = audio.audioSource;
            if(s == -1){
                audioSource?.pause();
            }else{
                audio.t = 0;
                let interval: number = ((1 / s) / 10);
                audio.time_id = setInterval(()=>{
                    if(audioSource){
                        audio.t += interval;
                        let volume: number = this.bgVolumeMax - audio.t / s;
                        if(volume <= 0){
                           clearInterval(audio.time_id);
                           audioSource?.pause();
                        }else{
                           audioSource.volume = volume <= 0 ? 0 :volume;
                        }
                    }
                },interval * 1000);
            }
            audio.playStatus = false;
        }
    }

    /**
     * 加载音效
     * @param loop 是否循环
     */
    public audioSourceLoop(loop: boolean): AudioSource{
        let audioSource: AudioSource = null;
        if(loop){//播放单次的时候具柄
            audioSource = this.getAudioSource(null,true,this.bgVolumeMax)
        }else{//循环播放的时候具柄
            audioSource = this.getAudioSource(null,false,1);
        }
        return audioSource;
    }


    /**
     * 得到一个播放音乐的控制类
     * @param clip 音效片段
     * @param loop 是否循环
     * @param volume 音量
     * @returns 播放类
     */
    public  getAudioSource(clip: AudioClip = null, loop: boolean = false, volume: number = 1): AudioSource{
        let audioSource: AudioSource = new AudioSource();
        if(clip){
            audioSource.clip = clip;
        }
        audioSource.loop = loop;
        audioSource.volume = volume;
        return audioSource;
    }
}
export default audioManager.ins();