package com.anren.omplayer;

import android.content.Context;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.webkit.CookieManager;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.ThemedReactContext;
import com.tencent.rtmp.ITXVodPlayListener;
import com.tencent.rtmp.TXLiveConstants;
import com.tencent.rtmp.TXVodPlayConfig;
import com.tencent.rtmp.TXVodPlayer;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by lcg on 2017/6/18.
 */
public class OMAudioPlayerTc  implements ITXVodPlayListener {


    private static final String TAG = OMAudioPlayerTc.class.getSimpleName();

    private int progress;
    private int duration;
    private int playable;

    public static final String EVENT_PROP_FAST_FORWARD = "canPlayFastForward";
    public static final String EVENT_PROP_SLOW_FORWARD = "canPlaySlowForward";
    public static final String EVENT_PROP_SLOW_REVERSE = "canPlaySlowReverse";
    public static final String EVENT_PROP_REVERSE = "canPlayReverse";
    public static final String EVENT_PROP_STEP_FORWARD = "canStepForward";
    public static final String EVENT_PROP_STEP_BACKWARD = "canStepBackward";

    public static final String EVENT_PROP_DURATION = "duration";
    public static final String EVENT_PROP_PLAYABLE_DURATION = "playableDuration";
    public static final String EVENT_PROP_CURRENT_TIME = "currentTime";
    public static final String EVENT_PROP_SEEK_TIME = "seekTime";
    public static final String EVENT_PROP_NATURALSIZE = "naturalSize";
    public static final String EVENT_PROP_WIDTH = "width";
    public static final String EVENT_PROP_HEIGHT = "height";
    public static final String EVENT_PROP_ORIENTATION = "orientation";

    public static final String EVENT_PROP_ERROR = "error";
    public static final String EVENT_PROP_WHAT = "what";
    public static final String EVENT_PROP_EXTRA = "extra";

    private OMAudioPlayerModuleTc mAudioPlayerModule = null;
    private Integer mPlayerId = 0;
    private TXVodPlayer mMediaPlayer;
    private String mToken = null;
    private String mSrcUriString = null;
    private boolean mMediaPlayerValid = false;
    private boolean isCompleted = false;
    private int mAudioDuration = 0;
    private int mAudioBufferedDuration = 0;

    private boolean mPauseBecauseCall = false;

    private Handler mProgressUpdateHandler = new Handler();
    private Runnable mProgressUpdateRunnable = null;

    private boolean mRepeat = false;
    private volatile Boolean mPaused = true;
    private boolean mMuted = false;
    private float mVolume = 1.0f;
    private float mRate = 1.0f;

    private AudioManager mAm;

    private boolean mAutoPause = false;

    private ReactApplicationContext mThemedReactContext = null;
    private TXVodPlayConfig mVodPlayConfig = null;

    private AudioManager.OnAudioFocusChangeListener mAudioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() {
        @Override
        public void onAudioFocusChange(int focusChange) {
            if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT
                    || focusChange == AudioManager.AUDIOFOCUS_LOSS) {
                // Pause playback
                if (mMediaPlayer.isPlaying()){
                    mAutoPause = true;
                    pause();
                }

            } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
                // Resume playback
                if (mAutoPause && !mMediaPlayer.isPlaying()) {
                    play();

                }
            }
        }
    };

    private boolean requestAudioFocus() {
        // Request audio focus for playback
        int result = mAm.requestAudioFocus(mAudioFocusChangeListener,
                // Use the music stream.
                AudioManager.STREAM_MUSIC,
                // Request permanent focus.
                AudioManager.AUDIOFOCUS_GAIN);
        return result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
    }

    public OMAudioPlayerTc(Integer playerId, OMAudioPlayerModuleTc audioPlayerModule, ReactApplicationContext themedReactContext){
        mPlayerId = playerId;
        mAudioPlayerModule = audioPlayerModule;
        mAm = (AudioManager) audioPlayerModule.getContext().getSystemService(Context.AUDIO_SERVICE);

        mThemedReactContext = themedReactContext;
//        initTelephonyListener();
//        initializeMediaPlayerIfNeeded();

//        mProgressUpdateRunnable = new Runnable() {
//            @Override
//            public void run() {
//
//                if (mMediaPlayerValid && !isCompleted &&!mPaused) {
//                    WritableMap event = Arguments.createMap();
//                    event.putDouble(EVENT_PROP_CURRENT_TIME, mMediaPlayer.getCurrentPosition() / 1000.0);
//                    event.putDouble(EVENT_PROP_PLAYABLE_DURATION, mAudioBufferedDuration / 1000.0); //TODO:mBufferUpdateRunnable
//                    event.putInt("id", mPlayerId);
//                    mAudioPlayerModule.sendEvent(OMAudioEvent.EVENT_AUDIO_PROGRESS, event);
//
//                    // Check for update after an interval
//                    // TODO: The update interval is fixed at 250. There is a property in React component that defines this value. Totally ignored !!!
//                    mProgressUpdateHandler.postDelayed(mProgressUpdateRunnable, 250);
//                }
//            }
//        };
    }

    private void initTelephonyListener() {
        TelephonyManager telephonyManager = (TelephonyManager)mAudioPlayerModule.getContext().getSystemService(Context.TELEPHONY_SERVICE);
        telephonyManager.listen(new PhoneStateListener(){
            @Override
            public void onCallStateChanged(int state, String incomingNumber) {
                if (state == TelephonyManager.CALL_STATE_RINGING || state == TelephonyManager.CALL_STATE_OFFHOOK) {

                    if (mMediaPlayer.isPlaying()) {
                        mPauseBecauseCall = true;
                        pause();
                    }

                }
                else if (state == TelephonyManager.CALL_STATE_IDLE) {
                    if (mPauseBecauseCall) {
                        mPauseBecauseCall = false;
                        play();
                    }
                }

                super.onCallStateChanged(state, incomingNumber);
            }
        }, PhoneStateListener.LISTEN_CALL_STATE);
    }

    private void initializeMediaPlayerIfNeeded(Map<String, String> headers) {
        if (mMediaPlayer == null) {
            mMediaPlayerValid = false;
            mMediaPlayer = new TXVodPlayer(this.mThemedReactContext);
            //new IjkMediaPlayer().
            mVodPlayConfig = new TXVodPlayConfig();

            mVodPlayConfig.setHeaders(headers);
            mMediaPlayer.setConfig(mVodPlayConfig);
            mMediaPlayer.setVodListener(this);
        }
    }


    public void setPausedModifier(final boolean paused) {

        if (!mMediaPlayerValid) {
            return;
        }
        if (mPaused == Boolean.valueOf(paused)) {
            return;
        }

        mPaused = paused;
        Log.d(TAG, "mPaused: mPaused=" + mPaused);

        isCompleted = false;
        if (mPaused){
            if (mMediaPlayer.isPlaying()) {
                mMediaPlayer.pause();
            }
        }
        else {
            if (requestAudioFocus() && !mMediaPlayer.isPlaying()) {
                mMediaPlayer.startPlay(mSrcUriString);
//                mProgressUpdateHandler.post(mProgressUpdateRunnable);
            }
        }
    }

    private void applyModifiers() {
        setRepeat(mRepeat);

        if (mPaused != null) {
            setPausedModifier(mPaused);
        }
//        if (mPaused){
//            if (mMediaPlayer.isPlaying()) {
//                mMediaPlayer.pause();
//            }
//        }
//        else {
//            if (requestAudioFocus()) {
//                mMediaPlayer.start();
//                mProgressUpdateHandler.post(mProgressUpdateRunnable);
//            }
//        }
        setMuted(mMuted);
    }

//    @Override
    public void onPrepared(TXVodPlayer mediaPlayer) {
        mMediaPlayerValid = true;

        WritableMap event = Arguments.createMap();
        event.putDouble(EVENT_PROP_DURATION, mediaPlayer.getDuration());
        event.putDouble(EVENT_PROP_CURRENT_TIME, mMediaPlayer.getCurrentPlaybackTime());

        // TODO: Actually check if you can.
        event.putBoolean(EVENT_PROP_FAST_FORWARD, true);
        event.putBoolean(EVENT_PROP_SLOW_FORWARD, true);
        event.putBoolean(EVENT_PROP_SLOW_REVERSE, true);
        event.putBoolean(EVENT_PROP_REVERSE, true);
        event.putBoolean(EVENT_PROP_FAST_FORWARD, true);
        event.putBoolean(EVENT_PROP_STEP_BACKWARD, true);
        event.putBoolean(EVENT_PROP_STEP_FORWARD, true);
        event.putInt("id", mPlayerId);

        mAudioPlayerModule.sendEvent(OMAudioEvent.EVENT_AUDIO_LOAD, event);

        applyModifiers();
    }

//    @Override
    public boolean onError(TXVodPlayer mediaPlayer, int what, int extra) {
        WritableMap error = Arguments.createMap();
        error.putInt(EVENT_PROP_WHAT, what);
        error.putInt(EVENT_PROP_EXTRA, extra);
        WritableMap event = Arguments.createMap();
        event.putMap(EVENT_PROP_ERROR, error);
        event.putInt("id", mPlayerId);

        mAm.abandonAudioFocus(mAudioFocusChangeListener);
        mAudioPlayerModule.sendEvent(OMAudioEvent.EVENT_AUDIO_ERROR, event);
        return true;
    }

//    @Override
//    public boolean onInfo(TXVodPlayer mediaPlayer, int what, int extra) {
//        WritableMap event = Arguments.createMap();
//        event.putInt("id", mPlayerId);
//
//        switch (what) {
//            case TXVodPlayer.MEDIA_INFO_BUFFERING_START:
//                mAudioPlayerModule.sendEvent(OMAudioEvent.EVENT_LOAD_STALLED, event);
//                break;
//            case TXVodPlayer.MEDIA_INFO_BUFFERING_END:
//                mAudioPlayerModule.sendEvent(OMAudioEvent.EVENT_LOAD_RESUME, event);
//                break;
//            case TXVodPlayer.MEDIA_INFO_VIDEO_RENDERING_START:
//                mAudioPlayerModule.sendEvent(OMAudioEvent.EVENT_AUDIO_READY_FOR_PLAY, event);
//                break;
//
//            default:
//        }
//        return false;
//    }

//    @Override
//    public void onBufferingUpdate(TXVodPlayer mediaPlayer, int percent) {
//        mAudioBufferedDuration = (int) Math.round((double) (mAudioDuration * percent) / 100.0);
//    }

//    @Override
    public void onCompletion(TXVodPlayer mediaPlayer) {
        isCompleted = true;
        mPaused = null;
        Log.d(TAG, "mPaused: " + null);
        WritableMap event = Arguments.createMap();
        event.putInt("id", mPlayerId);

        mAm.abandonAudioFocus(mAudioFocusChangeListener);

        mAudioPlayerModule.sendEvent(OMAudioEvent.EVENT_AUDIO_END, event);
        mediaPlayer.seek(0);
    }

    public void setAudioPlayerModule(OMAudioPlayerModuleTc audioPlayerModule) {
        mAudioPlayerModule = audioPlayerModule;
    }

    public void setAudioPlayerId(Integer playerId){
        mPlayerId = playerId;
    }

    public void setToken(final String tokenString) {

        mToken = tokenString;
        if (mSrcUriString == null || !mSrcUriString.endsWith(".m3u8")) {
            return;
        }
        setSrc(mSrcUriString);

    }

    public void setSrc(final String uriString) {

        mSrcUriString = uriString;
        if (uriString.endsWith(".m3u8") && mToken == null) {
            return;
        }
        mMediaPlayerValid = false;
        mAudioDuration = 0;
        mAudioBufferedDuration = 0;

        if (mMediaPlayer != null) {
            mMediaPlayer.stopPlay(false);
        }

        try {
            if (uriString.startsWith("http")) {
                // Use the shared CookieManager to access the cookies
                // set by WebViews inside the same app
                CookieManager cookieManager = CookieManager.getInstance();

                Uri parsedUrl = Uri.parse(uriString);
                Uri.Builder builtUrl = parsedUrl.buildUpon();

                String cookie = cookieManager.getCookie(builtUrl.build().toString());

                Map<String, String> headers = new HashMap<String, String>();

                if (cookie != null) {
                    headers.put("Cookie", cookie);
                }
                if (mToken != null) {
                    headers.put("User-Agent", mToken);
                }

//                mMediaPlayer.setDataSource(mAudioPlayerModule.getContext(), parsedUrl, headers);
                initializeMediaPlayerIfNeeded(headers);
            } else {
//                if (uriString.startsWith("content://")) {
//                    Uri parsedUrl = Uri.parse(uriString);
//                    mMediaPlayer.setDataSource(mAudioPlayerModule.getContext(), parsedUrl);
//                } else {
//                    mMediaPlayer.setDataSource(uriString);
//                }
                initializeMediaPlayerIfNeeded(null);
            }

        } catch (Exception e) {
            WritableMap event = Arguments.createMap();
            event.putString(OMVideoViewManager.PROP_SRC, uriString);
            event.putInt("id", mPlayerId);
            event.putString("error", e.getMessage());
            mAudioPlayerModule.sendEvent(OMAudioEvent.EVENT_AUDIO_ERROR, event);
            return;
        }

        WritableMap src = Arguments.createMap();
        src.putString(OMVideoViewManager.PROP_SRC_URI, uriString);

        WritableMap event = Arguments.createMap();
        event.putMap(OMVideoViewManager.PROP_SRC, src);
        event.putInt("id", mPlayerId);
        mAudioPlayerModule.sendEvent(OMAudioEvent.EVENT_AUDIO_LOAD_START, event);

        // not async to prevent random crashes on Android playback from local resource due to race conditions
//        try {
//            mMediaPlayer.prepareAsync();
//        } catch (Exception e) {
//            WritableMap prepareEvent = Arguments.createMap();
//            prepareEvent.putString(OMVideoViewManager.PROP_SRC, uriString);
//            prepareEvent.putInt("id", mPlayerId);
//            prepareEvent.putString("error", e.getMessage());
//            mAudioPlayerModule.sendEvent(OMAudioEvent.EVENT_AUDIO_ERROR, prepareEvent);
//        }
    }

    public void setRepeat(boolean repeat) {
        mRepeat = repeat;

        if (mMediaPlayerValid){
            mMediaPlayer.setLoop(mRepeat);
        }
    }

    public void setMuted(boolean muted) {
        mMuted = muted;

        if (!mMediaPlayerValid) {
            return;
        }


        if (mMuted) {
            mAm.setStreamVolume(AudioManager.STREAM_MUSIC, 0, 0);
        } else {
//            mAm.setStreamVolume(AudioManager.STREAM_MUSIC, (int)(mAm.getStreamMaxVolume(AudioManager.STREAM_MUSIC) * mVolume), 0);
            mAm.setStreamVolume(AudioManager.STREAM_MUSIC, mAm.getStreamVolume(AudioManager.STREAM_MUSIC), 0);
//            mVideoView.setVolume(mVolume, mVolume);
        }
//        if (mMuted) {
//            mMediaPlayer.setVolume(0, 0);
//        } else {
//            mMediaPlayer.setVolume(mVolume, mVolume);
//        }
    }

    public void setVolume(Float volume) {
        mVolume = volume;
        setMuted(mMuted);

//        mMediaPlayer.setVolume(volume, volume);
    }

    public void setRate(Float rate) {
        mRate = rate;

        if (mMediaPlayerValid) {
            mMediaPlayer.setRate(rate);
            // TODO: Implement this.
//            Log.e(OMVideoViewManager.REACT_CLASS, "Setting playback rate is not yet supported on Android");
        }
//        not implement
//        mMediaPlayer.setPlaybackSpeed(rate);
    }

    public void seek(int msec) {
        if (mMediaPlayerValid) {
            WritableMap event = Arguments.createMap();
            event.putDouble(EVENT_PROP_CURRENT_TIME, msec / 1000.0);
            event.putDouble(EVENT_PROP_SEEK_TIME, mAudioBufferedDuration / 1000.0);
            event.putInt("id", mPlayerId);
            mAudioPlayerModule.sendEvent(OMAudioEvent.EVENT_AUDIO_PROGRESS, event);
//            mAudioPlayerModule.sendEvent(OMAudioEvent.EVENT_AUDIO_SEEK, event);

            mMediaPlayer.seek(msec / 1000);
            if (isCompleted && mAudioDuration != 0 && msec < mAudioDuration) {
                isCompleted = false;
            }
        }
    }

    public void play() {
        if (requestAudioFocus()) {
            mPaused = false;
            mAutoPause = false;

            if (!mMediaPlayerValid) {
                return;
            }
            mMediaPlayer.resume();
//            mMediaPlayer.startPlay(mSrcUriString);
//            mProgressUpdateHandler.post(mProgressUpdateRunnable);

            WritableMap event = Arguments.createMap();
            event.putInt("id", mPlayerId);
            mAudioPlayerModule.sendEvent(OMAudioEvent.EVENT_AUDIO_RESUME, event);
        }
    }

    public void pause() {
        mPaused = true;

        if (!mMediaPlayerValid) {
            return;
        }

        mMediaPlayer.pause();

        WritableMap event = Arguments.createMap();
        event.putInt("id", mPlayerId);
        mAudioPlayerModule.sendEvent(OMAudioEvent.EVENT_AUDIO_STALLED, event);
    }

    public void stop() {

        if (!mMediaPlayerValid) {
            return;
        }

        if ( mMediaPlayer != null ) {
            mMediaPlayerValid = false;
            mMediaPlayer.stopPlay(true);
//            mediaPlayer.release();
            mMediaPlayer = null;
        }

//        mMediaPlayer.stop();
        mAm.abandonAudioFocus(mAudioFocusChangeListener);

        WritableMap event = Arguments.createMap();
        event.putInt("id", mPlayerId);
        mAudioPlayerModule.sendEvent(OMAudioEvent.EVENT_AUDIO_END, event);
    }



    @Override
    public void onPlayEvent(TXVodPlayer player, int event, Bundle param) {
        if (event != TXLiveConstants.PLAY_EVT_PLAY_PROGRESS) {
            String playEventLog = "receive event: " + event + ", " + param.getString(TXLiveConstants.EVT_DESCRIPTION);
            Log.d(TAG, playEventLog);
        }

        if (event == TXLiveConstants.PLAY_EVT_VOD_PLAY_PREPARED || event == TXLiveConstants.PLAY_EVT_VOD_LOADING_END) {
//            stopLoadingAnimation();
        }

        if (event == TXLiveConstants.PLAY_EVT_VOD_PLAY_PREPARED) {
            this.onPrepared(player);
//            BitrateView view = (BitrateView)findViewById(R.id.bitrate_view);
//            view.setDataSource(mVodPlayer.getSupportedBitrates());
//            view.setListener(new BitrateView.OnSelectBitrateListener() {
//                @Override
//                public void onBitrateIndex(int index) {
//                    mVodPlayer.setBitrateIndex(index);
//                }
//            });
//        }

//        if (event == TXLiveConstants.PLAY_EVT_PLAY_BEGIN) {
//            stopLoadingAnimation();
//            Log.d("AutoMonitor", "PlayFirstRender,cost=" +(System.currentTimeMillis()-mStartPlayTS));
//            if (mPhoneListener.isInBackground()) {
//                mVodPlayer.pause();
//            }



        } else if (event == TXLiveConstants.PLAY_EVT_PLAY_PROGRESS ) {

            progress = param.getInt(TXLiveConstants.EVT_PLAY_PROGRESS_MS);
            mAudioDuration = duration = param.getInt(TXLiveConstants.EVT_PLAY_DURATION_MS);
            playable = param.getInt(TXLiveConstants.EVT_PLAYABLE_DURATION_MS);

            WritableMap omEvent = Arguments.createMap();
            omEvent.putDouble(EVENT_PROP_CURRENT_TIME, progress / 1000.0);
            omEvent.putDouble(EVENT_PROP_PLAYABLE_DURATION, playable / 1000.0); //TODO:mBufferUpdateRunnable
            mAudioPlayerModule.sendEvent(OMAudioEvent.EVENT_AUDIO_PROGRESS.toString(), omEvent);

            Log.d(TAG, String.format("PROGRESS:%d:%d:%d", progress, duration, playable));
//            if (mSeekBar != null) {
//                mSeekBar.setProgress(progress);
//                mSeekBar.setSecondaryProgress(playable);
//            }
//            if (mTextStart != null) {
//                mTextStart.setText(String.format("%02d:%02d",progress/1000/60,progress/1000%60));
//            }
//            if (mTextDuration != null) {
//                mTextDuration.setText(String.format("%02d:%02d",duration/1000/60,duration/1000%60));
//            }
//            if (mSeekBar != null) {
//                mSeekBar.setMax(duration);
//            }
            return;
        } else if (event == TXLiveConstants.PLAY_EVT_PLAY_END) {
            Log.d(TAG, "mVodPlayerPreload resume");
            onCompletion(player);
        } else if (event == TXLiveConstants.PLAY_ERR_NET_DISCONNECT || event == TXLiveConstants.PLAY_ERR_FILE_NOT_FOUND || event == TXLiveConstants.PLAY_ERR_HLS_KEY) {
            player.pause();
            onError(player, event, event);
//            stopPlayVod();
//            mVideoPlay = false;
//            mVideoPause = false;
//            if (mTextStart != null) {
//                mTextStart.setText("00:00");
//            }
//            if (mSeekBar != null) {
//                mSeekBar.setProgress(0);
//            }

        } else if (event == TXLiveConstants.PLAY_EVT_PLAY_LOADING){
//            startLoadingAnimation();
        } else if (event == TXLiveConstants.PLAY_EVT_RCV_FIRST_I_FRAME) {
//            stopLoadingAnimation();
//            findViewById(R.id.playerHeaderView).setVisibility(View.GONE);
//            if (mPhoneListener.isInBackground()) {
//                mVodPlayer.pause();
//            }
//        } else if (event == TXLiveConstants.PLAY_EVT_CHANGE_RESOLUTION) {
        } else if (event == TXLiveConstants.PLAY_WARNING_RECONNECT) {
            player.resume();
//            startLoadingAnimation();
        } else if (event == TXLiveConstants.PLAY_EVT_CHANGE_ROTATION) {
            return;
        }

        if (event < 0) {
            Toast.makeText(mThemedReactContext, param.getString(TXLiveConstants.EVT_DESCRIPTION), Toast.LENGTH_SHORT).show();
        }
    }


    @Override
    public void onNetStatus(TXVodPlayer player, Bundle status) {

    }

}
