package de.frajul.endlessroll.sounds;

import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;
import android.support.annotation.RawRes;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

import de.frajul.endlessroll.R;
import de.frajul.endlessroll.main.GameActivity;
import de.frajul.endlessroll.main.GameLog;

/**
 * Created by Julian on 18.12.2015.
 */
public class SoundManager {

    private Context context;
    private Random random;
    private SoundPool soundPool;
    private boolean soundsMuted;
    private boolean musicMuted;

    public final Music menuMusic;
    private List<Music> gameMusicList = new ArrayList<>();
    private int currentGameMusicIndex = 0;

    public final Sound goalSound;
    public final Sound dieSound;
    public final Sound collectStarSound;
    public final Sound collectEnergySound;
    public final Sound countdownSound;
    public final Sound explosionSound;
    public final Sound fireworkSound;
    public final Sound stasisSound;
    public final Sound mushroomSound;
    public final Sound springSound;
    public final Sound placeToolSound;
    public final Sound magnetSound;

    private final List<SoundStream> allStartedStreams = Collections.synchronizedList(new ArrayList<SoundStream>());

    public SoundManager(GameActivity gameActivity) {
        this.context = gameActivity;
        random = new Random();
        soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);

        menuMusic = new Music(gameActivity, gameActivity, R.raw.music_menu);
        menuMusic.getPlayer().setLooping(true);
        gameMusicList.add(createGameMusic(gameActivity, R.raw.music_game_1));
        gameMusicList.add(createGameMusic(gameActivity, R.raw.music_game_2));
        gameMusicList.add(createGameMusic(gameActivity, R.raw.music_game_3));

        goalSound = new Sound(loadSound(R.raw.sound_goal));
        dieSound = new Sound(loadSound(R.raw.sound_die));
        collectStarSound = new Sound(loadSound(R.raw.sound_collect_star), .7f);
        collectEnergySound = new Sound(loadSound(R.raw.sound_collect_energy));
        countdownSound = new Sound(loadSound(R.raw.sound_countdown));
        explosionSound = new Sound(loadSound(R.raw.sound_explosion), 2);
        fireworkSound = new Sound(loadSound(R.raw.sound_firework));
        stasisSound = new Sound(loadSound(R.raw.sound_stasis), 1.3f, true);
        mushroomSound = new Sound(loadSound(R.raw.sound_mushroom));
        springSound = new Sound(loadSound(R.raw.sound_spring));
        placeToolSound = new Sound(loadSound(R.raw.sound_place_tool), 1.5f);
        magnetSound = new Sound(loadSound(R.raw.sound_magnet), 0.8f, true);
    }

    private Music createGameMusic(GameActivity gameActivity, @RawRes int musicId) {
        Music gameMusic = new Music(gameActivity, context, musicId);
        gameMusic.getPlayer().setLooping(true);
        return gameMusic;
    }

    public void randomizeCurrentGameMusic() {
        getCurrentGameMusic().stop();
        int randomIndex = random.nextInt(gameMusicList.size());
        currentGameMusicIndex = randomIndex;
    }

    public Music getCurrentGameMusic() {
        return gameMusicList.get(currentGameMusicIndex);
    }

    public void setSoundsMuted(boolean soundsMuted) {
        this.soundsMuted = soundsMuted;
        synchronized (allStartedStreams) {
            for (SoundStream stream : allStartedStreams) {
                float systemVolume = getSystemVolume();
                soundPool.setVolume(stream.getId(), systemVolume * stream.getModifiedVolume(),
                        systemVolume * stream.getModifiedVolume());
            }
        }
    }

    public void setMusicMuted(boolean musicMuted) {
        this.musicMuted = musicMuted;
        menuMusic.setMuted(musicMuted);
        for (Music gameMusic : gameMusicList)
            gameMusic.setMuted(musicMuted);
    }

    public boolean isSoundsMuted() {
        return soundsMuted;
    }

    public boolean isMusicMuted() {
        return musicMuted;
    }

    public void activityPause() {
        soundPool.autoPause();
        for (Music gameMusic : gameMusicList)
            gameMusic.activityPause();
        menuMusic.activityPause();
    }

    public void activityResume() {
        soundPool.autoResume();
        for (Music gameMusic : gameMusicList)
            gameMusic.activityResume();
        menuMusic.activityResume();
    }

    public void pauseAllSounds() {
        synchronized (allStartedStreams) {
            for (SoundStream stream : allStartedStreams)
                soundPool.pause(stream.getId());
        }
    }

    public void resumeAllSounds() {
        synchronized (allStartedStreams) {
            for (SoundStream stream : allStartedStreams)
                soundPool.resume(stream.getId());
        }
    }

    public void destroy() {
        menuMusic.getPlayer().release();
        for (Music gameMusic : gameMusicList)
            gameMusic.getPlayer().release();
        soundPool.release();
    }

    public int loadSound(int id) {
        int sound = soundPool.load(context, id, 1);
        return sound;
    }

    public SoundStream playSound(Sound sound) {
        float systemVolume = getSystemVolume();
        int streamId = soundPool.play(sound.getSoundId(), systemVolume * sound.getVolume(),
                systemVolume * sound.getVolume(), 1, sound.isLooping() ? -1 : 0, 1);
        if (streamId == 0)
            GameLog.e("SoundId: " + sound.getSoundId() + " cannot be played");
        SoundStream soundStream = new SoundStream(streamId, sound.getVolume());
        allStartedStreams.add(soundStream);
        return soundStream;
    }

    public void onStreamVolumeChanged(SoundStream stream) {
        if (!soundsMuted) {
            float systemVolume = getSystemVolume();
            soundPool.setVolume(stream.getId(), systemVolume * stream.getModifiedVolume(),
                    systemVolume * stream.getModifiedVolume());
        }
    }

    public void stopSound(SoundStream stream) {
        allStartedStreams.remove(stream);
        soundPool.stop(stream.getId());
    }

    public void stopAllSounds() {
        synchronized (allStartedStreams) {
            for (SoundStream stream : allStartedStreams)
                soundPool.stop(stream.getId());
        }
        allStartedStreams.clear();
    }

    private float getSystemVolume() {
        if (soundsMuted)
            return 0;
        AudioManager manager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        float volume = manager.getStreamVolume(AudioManager.STREAM_MUSIC);
        float maxVolume = manager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
        return volume / maxVolume;
    }

}
