import { Node, AudioSource, AudioClip, resources, director, assetManager } from 'cc';


interface IPlayOptions {
    bundleName?: string,
    volume?: number,
}


export enum AudioClipName {
    bgm = "Audio/bgm",
    button_ok = "Audio/button_ok",
    start = "Audio/start",
    upgrade = "Audio/upgrade",
    crash = "Audio/crash",
    brake = "Audio/brake",
    win = "Audio/win",
    helico = "Audio/helico",
}

/**
 * @en
 * this is a sington class for audio play, can be easily called from anywhere in you project.
 * @zh
 * 这是一个用于播放音频的单件类，可以很方便地在项目的任何地方调用。
 */
export class AudioMgr {

    private static _ins: AudioMgr;
    public static get ins(): AudioMgr {
        if (!this._ins) {
            this._ins = new AudioMgr();
        }
        return this._ins;
    }

    private _audioSource: AudioSource;
    private _musicVolume = 1.0;
    private _musicVolumeScale = 1.0;
    private _soundVolume = 1.0;

    constructor() {
        //@en create a node as audioMgr
        //@zh 创建一个节点作为 audioMgr
        let audioMgr = new Node();
        audioMgr.name = '__audioMgr__';

        // 不要加到场景上，这样就不会切场景重播了
        // director.getScene().addChild(audioMgr);
        // director.addPersistRootNode(audioMgr);

        this._audioSource = new AudioSource();
        // this._audioSource = audioMgr.addComponent(AudioSource);

        // this._audioSource.onEnable = () => {
        //
        // }
        // this._audioSource.onDisable = () => {
        //
        // }
    }

    public get audioSource() {
        return this._audioSource;
    }

    public set musicVolume(v: number) {
        this._musicVolume = v;
        this._audioSource.volume = this._musicVolume * this._musicVolumeScale;
    }

    public get musicVolume() {
        return this._musicVolume;
    }

    public set soundVolume(v: number) {
        this._soundVolume = v;
    }
    public get soundVolume() {
        return this._soundVolume;
    }

    /**
     * @en
     * play short audio, such as strikes,explosions
     * @zh
     * 播放短音频,比如 打击音效，爆炸音效等
     * @param sound clip or url for the audio
     * @param options
     */
    playOneShot(sound: AudioClip | AudioClipName | string, options: IPlayOptions = {}) {

        options = {
            bundleName: "resources",
            volume: this.soundVolume,
            ...options
        };

        if (sound instanceof AudioClip) {
            this.audioSource.playOneShot(sound, options.volume);
        } else {
            let bundle = assetManager.getBundle(options.bundleName);
            bundle.load(sound, (err, clip: AudioClip) => {
                if (err) {
                    console.log(err);
                } else {
                    this.audioSource.playOneShot(clip, options.volume);
                }
            });
        }
    }

    /**
     * @en
     * play long audio, such as the bg music
     * @zh
     * 播放长音频，比如 背景音乐
     * @param sound clip or url for the sound
     * @param options
     */
    play(sound: AudioClip | AudioClipName | string, options: { loop?: boolean } & IPlayOptions = {}) {

        options = {
            bundleName: "resources",
            loop: true,
            volume: 1,
            ...options
        };

        this._musicVolumeScale = options.volume;
        if (sound instanceof AudioClip) {
            this.audioSource.clip = sound;
            this.audioSource.loop = options.loop;
            this.audioSource.play();
            this.audioSource.volume = this._musicVolume * this._musicVolumeScale;
        } else {
            let bundle = assetManager.getBundle(options.bundleName);
            bundle.load(sound, (err, clip: AudioClip) => {
                if (err) {
                    console.log(err);
                } else {
                    this.audioSource.clip = clip;
                    this.audioSource.loop = options.loop;
                    this.audioSource.play();
                    this.audioSource.volume = this._musicVolume * this._musicVolumeScale;
                }
            });
        }
    }

    /**
     * stop the audio play
     */
    stop() {
        this._audioSource.stop();
    }

    /**
     * pause the audio play
     */
    pause() {
        this._audioSource.pause();
    }

    /**
     * resume the audio play
     */
    resume() {
        this._audioSource.play();
    }
}
