import { _decorator,AudioClip, AudioSource} from 'cc';
import { Singleton } from './Singleton';
import { bundleMgr } from './BundleManager';
import { GameConst } from '../common/GameConst';
import { Logger } from '../extend/Logger';
import Utils from '../utils/Utils';
import { settingData } from '../../user/SettingData';


const { ccclass, property } = _decorator;

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

@ccclass('AudioManager')
class AudioManager extends Singleton{
    //缓存的音乐
    private cachedAudioArr: Array<IAudioData> = [];

    /**
     * 预加载音乐 
     * 这儿前面 bundleManager资源包已经 loadLaunchBundles加载过了
     * 可以直接 再次
     */
    public async initialize(): Promise<void> {
        const audioAssets = Object.entries(GameConst.audios)
            .map(([key, path]) => ({
                path: path,
                type: AudioClip
            }))
            .filter(asset => !!asset.path);
        await bundleMgr.loadMultipleAssets(GameConst.bundleName.audios,
            audioAssets,
            (progress) => {/*进度条0~1*/},
            (err:Error, clip: AudioClip, path) => {
                if(err) {
                    Logger.error("加载资源失败:", err);
                }else{
                    this.cachedAudioArr.push({
                        clip: clip, 
                        audioSource: null, 
                        path: path,
                        playStatus: false,
                        totalTime: clip.getDuration(),
                        time_id: -1,
                        t: 0
                    });
                }
            }
        );
    }

    /**
     * 播放音效 不会两个相同的音乐重复播放 可以停止
     * @param path 播放音乐的路径
     * @param loop 是否循环播放
     * @param s 如果为-1则最大音量立即播放 如果为其他则慢慢音量递增起来播放
     * @returns 
     */
    private bgVolumeMax: number = 0.8;
    public async play(path: string,loop: boolean = false,s: number = -1): Promise<void> {
        if(Utils.isNull(path) 
            ||!settingData.data.bgMusic)return;
        const fun = (audio:IAudioData)=>{
            if(audio.audioSource == null){
               audio.audioSource = this.audioSourceLoop(loop);
            }
            if(audio.playStatus)return;
            audio.audioSource.clip = audio.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{
            await bundleMgr.loadAsset(GameConst.bundleName.audios,path,
                AudioClip,(err: Error, clip: AudioClip) => {
                if(err) {
                    Logger.error("加载资源失败:", 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 overlap 是否可以重复两个同一个音效连续播放
     * @returns 
     */
    public async playOneShot(path: string,overlap: boolean = true): Promise<void> {
        if(Utils.isNull(path) 
            ||!settingData.data.soundFx)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;
                setTimeout(()=>{
                    audio.playStatus = false;
                },audio.totalTime * 1000)
            }
        }
        let a: IAudioData = this.cachedAudioArr.find(e =>e.path == path);
        if(a){
           fun(a);
        }else{
            await bundleMgr.loadAsset(GameConst.bundleName.audios,path,
                AudioClip,(err: Error, clip: AudioClip) => {
                if(err) {
                    Logger.error("加载资源失败:", 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 {
        if(Utils.isNull(path))return;
        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 const audioMgr = AudioManager.ins();
