import DebugMgr from "./DebugMgr";
import MTimer from "../MComponents/MTimer";

export default class SoundMgr {
    private static _instance: SoundMgr = null;
    public static get instance(): SoundMgr {
        if (!this._instance) {
            this._instance = new SoundMgr();
        }

        return this._instance;
    }
    public effectEnabled = false;

    private _enabled: boolean = false;
    public set enabled(v: boolean) {
        this.musicEnabled = v;
        this.effectEnabled = v;
        this._enabled = v;
    }
    public get enabled() {
        return this._enabled;
    }

    private _musicEnabled: boolean = false;
    public get musicEnabled() {
        return this._musicEnabled;
    }
    public set musicEnabled(v: boolean) {
        if (v == true) {
            this.playMusic();
        } else {
            this.stopMusic();
        }
        this._musicEnabled = v;
    }

    private music: egret.Sound = null;
    private musicChannel: egret.SoundChannel = null;
    private loopChannelMap: { [name: string]: egret.SoundChannel } = {}
    private effectPool: { [name: string]: PoolSound[] } = {}
    public firstSeted = false;

    public setMusic(url: string) {
        this.music = RES.getRes(url);
        if (this.musicChannel) {
            this.playMusic();
        }
    }

    constructor() {
        MTimer.onFrame(() => {
            DebugMgr.instance.setLog(this.t.toString());
        });
    }

    public playMusic() {
        if (this.music == null) {
            console.warn("music do not set");
            return;
        }
        this.musicChannel && this.musicChannel.stop();
        this.musicChannel = this.music.play(0, 0);
    }

    public stopMusic() {
        this.musicChannel && (this.musicChannel.stop());
    }

    public playEffect(name: string, loop: boolean = false) {
        if (!this.effectEnabled) return;

        let poolSound = this.createSound(name, loop);
        let channel = poolSound.sound.play(0, loop ? 0 : 1);
        if (loop) {
            if (this.loopChannelMap[name]) {
                this.loopChannelMap[name].stop();
            }
            this.loopChannelMap[name] = channel;
        } else {
            return new Promise<void>(resolve => {
                channel.addEventListener(egret.Event.SOUND_COMPLETE, () => {
                    this.recycleSound(poolSound);
                    resolve();
                }, this);
            });
        }
    }

    public stopLoopEffect(name: string) {
        if (this.loopChannelMap[name]) {
            this.loopChannelMap[name].stop();
        }
    }

    private t: number = 0;

    private createSound(name: string, loop: boolean): PoolSound {
        let soundList = this.effectPool[name];
        if (!soundList || soundList.length <= 0) {
            let poolSound = new PoolSound(name, RES.getRes(name), loop);
            if (poolSound.name == "shoot_mp3") {
                this.t++;
            }
            return poolSound;
        } else {
            return soundList.pop();
        }
    }

    private recycleSound(poolSound: PoolSound) {
        delete this.loopChannelMap[poolSound.name];
        this.effectPool[poolSound.name] = this.effectPool[poolSound.name] || [];
        this.effectPool[poolSound.name].push(poolSound);
    }
}

class PoolSound {
    private loop = false;
    public onRecycle = (sound: PoolSound) => { }
    public sound: egret.Sound = null;
    public name: string = null;
    constructor(name: string, sound: egret.Sound, loop: boolean) {
        this.name = name;
        this.sound = sound;
        this.loop = loop;
    }
}