package com.netease.nim.uikit.common.media.audioplayer;

import android.content.Context;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Handler;
import android.text.TextUtils;

import com.netease.nim.uikit.R;
import com.netease.nim.uikit.common.util.log.LogUtil;
import com.netease.nimlib.sdk.media.player.AudioPlayer;
import com.netease.nimlib.sdk.media.player.OnPlayListener;

abstract public class BaseAudioControl<T> {

    interface AudioControllerState {
        int stop = 0;
        int ready = 1;
        int playing = 2;
    }

    private int state;
    protected boolean isEarPhoneModeEnable = true; // 是否是听筒模式

    public interface AudioControlListener {
        //AudioControl准备就绪，已经postDelayed playRunnable，不等同于AudioPlayer已经开始播放
        public void onAudioControllerReady(Playable playable);

        /**
         * 结束播放
         */
        public void onEndPlay(Playable playable);

        /**
         * 显示播放过程中的进度条
         *
         * @param curPosition 当前进度，如果传-1则自动获取进度
         */
        public void updatePlayingProgress(Playable playable, long curPosition);
    }

    protected AudioControlListener audioControlListener;

    protected Context mContext;
    protected AudioPlayer currentAudioPlayer;
    protected Playable currentPlayable;

    protected boolean needSeek = false;
    protected long seekPosition;

    private MediaPlayer mSuffixPlayer = null;
    private boolean mSuffix = false;
    protected Handler mHandler = new Handler();

    private BasePlayerListener basePlayerListener = null;

    protected void setOnPlayListener(Playable playingPlayable, AudioControlListener audioControlListener) {
        this.audioControlListener = audioControlListener;

        basePlayerListener = new BasePlayerListener(currentAudioPlayer, playingPlayable);
        currentAudioPlayer.setOnPlayListener(basePlayerListener);
        basePlayerListener.setAudioControlListener(audioControlListener);
    }

    public void setEarPhoneModeEnable(boolean isEarPhoneModeEnable) {
        this.isEarPhoneModeEnable = isEarPhoneModeEnable;
        if (isEarPhoneModeEnable) {
            updateAudioStreamType(AudioManager.STREAM_VOICE_CALL);
        } else {
            updateAudioStreamType(AudioManager.STREAM_MUSIC);
        }
    }

    @SuppressWarnings("unchecked")
    public void changeAudioControlListener(AudioControlListener audioControlListener) {
        this.audioControlListener = audioControlListener;

        if (isPlayingAudio()) {
            OnPlayListener onPlayListener = currentAudioPlayer.getOnPlayListener();
            if (onPlayListener != null) {
                ((BasePlayerListener) onPlayListener).setAudioControlListener(audioControlListener);
            }
        }
    }

    public AudioControlListener getAudioControlListener() {
        return audioControlListener;
    }

    public BaseAudioControl(Context context, boolean suffix) {
        this.mContext = context;
        this.mSuffix = suffix;
    }

    protected void playSuffix() {
        if (mSuffix) {
            mSuffixPlayer = MediaPlayer.create(mContext, R.raw.audio_end_tip);
            mSuffixPlayer.setLooping(false);
            mSuffixPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mSuffixPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    mSuffixPlayer.release();
                    mSuffixPlayer = null;
                }
            });
            mSuffixPlayer.start();
        }
    }

    protected boolean startAudio(
            Playable playable,
            AudioControlListener audioControlListener,
            int audioStreamType,
            boolean resetOrigAudioStreamType,
            long delayMillis) {
        String filePath = playable.getPath();
        if (TextUtils.isEmpty(filePath)) {
            return false;
        }

        //正在播放，停止播放
        if (isPlayingAudio()) {
            stopAudio();
            //如果相等，就是同一个对象了
            if (currentPlayable.isAudioEqual(playable)) {
                return false;
            }
        }

        state = AudioControllerState.stop;

        currentPlayable = playable;
        currentAudioPlayer = new AudioPlayer(mContext);
        currentAudioPlayer.setDataSource(filePath);

        setOnPlayListener(currentPlayable, audioControlListener);

        if (resetOrigAudioStreamType) {
            this.origAudioStreamType = audioStreamType;
        }
        this.currentAudioStreamType = audioStreamType;

        mHandler.postDelayed(playRunnable, delayMillis);

        state = AudioControllerState.ready;
        if (audioControlListener != null) {
            audioControlListener.onAudioControllerReady(currentPlayable);
        }

        return true;
    }

    Runnable playRunnable = new Runnable() {

        @Override
        public void run() {
            if (currentAudioPlayer == null) {
                LogUtil.audio("playRunnable run when currentAudioPlayer == null");
                return;
            }

            currentAudioPlayer.start(currentAudioStreamType);
        }
    };

    private int origAudioStreamType;
    private int currentAudioStreamType;

    public int getCurrentAudioStreamType() {
        return currentAudioStreamType;
    }

    protected int getUserSettingAudioStreamType() {
        // 听筒模式/扬声器模式
        if (isEarPhoneModeEnable) {
            return AudioManager.STREAM_VOICE_CALL;
        } else {
            return AudioManager.STREAM_MUSIC;
        }
    }

    protected void resetAudioController(Playable playable) {
        currentAudioPlayer.setOnPlayListener(null);
        currentAudioPlayer = null;

        state = AudioControllerState.stop;
    }

    //playing or ready
    public boolean isPlayingAudio() {
        if (currentAudioPlayer != null) {
            return state == AudioControllerState.playing
                    || state == AudioControllerState.ready;
        } else {
            return false;
        }
    }

    //stop or cancel
    public void stopAudio() {
        if (state == AudioControllerState.playing) {
            //playing->stop
            currentAudioPlayer.stop();
        } else if (state == AudioControllerState.ready) {
            //ready->cancel
            mHandler.removeCallbacks(playRunnable);
            resetAudioController(currentPlayable);

            if (audioControlListener != null) {
                audioControlListener.onEndPlay(currentPlayable);
            }
        }
    }

    public boolean updateAudioStreamType(int audioStreamType) {
        if (!isPlayingAudio()) {
            return false;
        }

        if (audioStreamType == getCurrentAudioStreamType()) {
            return false;
        }

        changeAudioStreamType(audioStreamType);
        return true;
    }

    public boolean restoreAudioStreamType() {
        if (!isPlayingAudio()) {
            return false;
        }

        if (origAudioStreamType == getCurrentAudioStreamType()) {
            return false;
        }

        changeAudioStreamType(origAudioStreamType);
        return true;
    }

    private void changeAudioStreamType(int audioStreamType) {
        if (currentAudioPlayer.isPlaying()) {
            seekPosition = currentAudioPlayer.getCurrentPosition();
            needSeek = true;
            currentAudioStreamType = audioStreamType;
            currentAudioPlayer.start(audioStreamType);
        } else {
            currentAudioStreamType = origAudioStreamType;
        }
    }

    public class BasePlayerListener implements OnPlayListener {
        protected AudioPlayer listenerPlayingAudioPlayer;
        protected Playable listenerPlayingPlayable;
        protected AudioControlListener audioControlListener;

        public BasePlayerListener(AudioPlayer playingAudioPlayer, Playable playingPlayable) {
            listenerPlayingAudioPlayer = playingAudioPlayer;
            listenerPlayingPlayable = playingPlayable;
        }

        public void setAudioControlListener(AudioControlListener audioControlListener) {
            this.audioControlListener = audioControlListener;
        }

        protected boolean checkAudioPlayerValid() {
            if (currentAudioPlayer != listenerPlayingAudioPlayer) {
                return false;
            }

            return true;
        }

        @Override
        public void onPrepared() {
            if (!checkAudioPlayerValid()) {
                return;
            }

            state = AudioControllerState.playing;
            if (needSeek) {
                needSeek = false;
                listenerPlayingAudioPlayer.seekTo((int) seekPosition);
            }
        }

        @Override
        public void onPlaying(long curPosition) {
            if (!checkAudioPlayerValid()) {
                return;
            }

            if (audioControlListener != null) {
                audioControlListener.updatePlayingProgress(listenerPlayingPlayable, curPosition);
            }
        }

        @Override
        public void onInterrupt() {
            if (!checkAudioPlayerValid()) {
                return;
            }

            resetAudioController(listenerPlayingPlayable);
            if (audioControlListener != null) {
                audioControlListener.onEndPlay(currentPlayable);
            }

        }

        @Override
        public void onError(String error) {
            if (!checkAudioPlayerValid()) {
                return;
            }

            resetAudioController(listenerPlayingPlayable);
            if (audioControlListener != null) {
                audioControlListener.onEndPlay(currentPlayable);
            }
        }

        @Override
        public void onCompletion() {
            if (!checkAudioPlayerValid()) {
                return;
            }

            resetAudioController(listenerPlayingPlayable);
            if (audioControlListener != null) {
                audioControlListener.onEndPlay(currentPlayable);
            }

            playSuffix();
        }
    }

    ;

    public void startPlayAudio(
            T t,
            AudioControlListener audioControlListener) {
        startPlayAudio(t, audioControlListener, getUserSettingAudioStreamType());
    }

    public void startPlayAudio(
            T t,
            AudioControlListener audioControlListener,
            int audioStreamType) {
        startPlayAudioDelay(0, t, audioControlListener, audioStreamType);
    }

    public void startPlayAudioDelay(long delayMillis, T t, AudioControlListener audioControlListener) {
        startPlayAudioDelay(delayMillis, t, audioControlListener, getUserSettingAudioStreamType());
    }

    public abstract void startPlayAudioDelay(long delayMillis, T t, AudioControlListener audioControlListener, int audioStreamType);

    public abstract T getPlayingAudio();
}
