package co.pixelbeard.theanfieldwrap.videoPlayer;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.media.session.MediaSessionManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.text.Html;
import android.util.Log;
import android.view.KeyEvent;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;

import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.source.dash.DashMediaSource;
import com.google.android.exoplayer2.source.hls.HlsMediaSource;
import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
import com.google.android.exoplayer2.util.Util;

import org.parceler.Parcels;

import co.pixelbeard.theanfieldwrap.R;
import co.pixelbeard.theanfieldwrap.data.Video;
import co.pixelbeard.theanfieldwrap.playerService.PlaybackStatus;
import co.pixelbeard.theanfieldwrap.playerService.PodcastStorageUtil;
import co.pixelbeard.theanfieldwrap.playerService.player2.LogHelper;

import static co.pixelbeard.theanfieldwrap.playerService.MediaConstants.ACTION_NEXT;
import static co.pixelbeard.theanfieldwrap.playerService.MediaConstants.ACTION_PAUSE;
import static co.pixelbeard.theanfieldwrap.playerService.MediaConstants.ACTION_PLAY;
import static co.pixelbeard.theanfieldwrap.playerService.MediaConstants.ACTION_PREVIOUS;
import static co.pixelbeard.theanfieldwrap.playerService.MediaConstants.ACTION_STOP;
import static co.pixelbeard.theanfieldwrap.playerService.MediaConstants.MEDIA_SESSION_ID;
import static co.pixelbeard.theanfieldwrap.playerService.MediaConstants.NOTIFICATION_ID;

public class VideoPlayerService extends Service implements Player.EventListener,
        AudioManager.OnAudioFocusChangeListener {

    // The volume we set the media player to when we lose audio focus, but are
    // allowed to reduce the volume instead of stopping playback.
    public static final float VOLUME_DUCK = 0.2f;

    // Binder given to clients
    private final IBinder iBinder = new LocalBinder();
    public SimpleExoPlayer exoPlayer;
    private int currentWindow;

    // MediaSession
    private MediaSessionManager mediaSessionManager;
    private MediaSessionCompat mediaSession;
    private MediaControllerCompat.TransportControls transportControls;
    // Used to pause/resume MediaPlayer
    private long resumePosition;

    // AudioFocus
    private AudioManager audioManager;

    // Currently queued podcast
    private Bitmap albumArt;

    // Handle incoming phone calls
    private boolean ongoingCall = false;
    private PhoneStateListener phoneStateListener;
    private TelephonyManager telephonyManager;

    private Video mVideo = null;
    // The volume we set the media player when we have audio focus.
    public static final float VOLUME_NORMAL = 1.0f;
    private static final String TAG = VideoPlayerService.class.getSimpleName();
    // we don't have audio focus, and can't duck (play at a low volume)
    private static final int AUDIO_NO_FOCUS_NO_DUCK = 0;
    // we don't have focus, but can duck (play at a low volume)
    private static final int AUDIO_NO_FOCUS_CAN_DUCK = 1;
    // we have full audio focus
    private static final int AUDIO_FOCUSED = 2;
    private final IntentFilter mAudioNoisyIntentFilter =
            new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
    private boolean mAudioNoisyReceiverRegistered;
    private int mCurrentAudioFocusState = AUDIO_NO_FOCUS_NO_DUCK;
    private boolean mPlayOnFocusGain;
    /**
     * ACTION_AUDIO_BECOMING_NOISY -- change in audio outputs
     */
    private BroadcastReceiver becomingNoisyReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            //pause audio on ACTION_AUDIO_BECOMING_NOISY
            if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
                pauseMedia();
                buildNotification(PlaybackStatus.PAUSED);
            }
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
//        callStateListener();
        registerAudioNoisyReceiver();
    }

    //The system calls this method when an activity, requests the service be started
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        try {
            //Load data from SharedPreferences
            Video video = Parcels.unwrap(intent.getParcelableExtra("VIDEO"));
            if (video != null) {
                this.mVideo = video;

                if (albumArt == null) {
                    Glide.with(this)
                            .asBitmap()
                            .load(mVideo.getThumbnail())
                            .into(new CustomTarget<Bitmap>() {
                                @Override
                                public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
                                    albumArt = resource;
                                    if (mediaIsPlaying()) {
                                        buildNotification(PlaybackStatus.PLAYING);
                                    }
                                }

                                @Override
                                public void onLoadCleared(@Nullable Drawable placeholder) {
                                }
                            });
                }
            }
        } catch (Exception e) {
            stopSelf();
        }

        //Request audio focus
        if (!requestAudioFocus()) {
            //Could not gain focus
            stopSelf();
        }

        if (mediaSessionManager == null) {
            try {
                initMediaSession();
                initializePlayer();
            } catch (RemoteException e) {
                e.printStackTrace();
                stopSelf();
            }
            buildNotification(PlaybackStatus.PLAYING);
        }
        //Handle Intent action from MediaSession.TransportControls
        handleIncomingActions(intent);
        return START_STICKY;
    }

    /**
     * Service lifecycle methods
     */
    @Override
    public IBinder onBind(Intent intent) {


        return iBinder;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (exoPlayer != null) {
            stopMedia();
            releasePlayer();
        }
        removeAudioFocus();
        //Disable the PhoneStateListener
        if (phoneStateListener != null) {
            telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
        }

        removeNotification();

        //unregister BroadcastReceivers
        unregisterAudioNoisyReceiver();

        stopSelf();

        if (mediaSession != null) {
            mediaSession.release();
        }
    }

    private void initializePlayer() {


        if (mVideo != null) {
            exoPlayer = ExoPlayerFactory.newSimpleInstance(this);

            exoPlayer.setPlayWhenReady(true);

            Uri uri = Uri.parse(mVideo.getVideoUrl());
            MediaSource mediaSource = buildMediaSource(uri);
            exoPlayer.prepare(mediaSource, true, false);
            exoPlayer.seekTo(currentWindow, resumePosition);
        }

    }

    private MediaSource buildMediaSource(Uri uri) {
        return buildMediaSource(uri, uri.getLastPathSegment());
    }

    private MediaSource buildMediaSource(Uri uri, @Nullable String overrideExtension) {

        DefaultHttpDataSourceFactory dataSourceFactory = new DefaultHttpDataSourceFactory("The-Anfield-Wrap");

        @C.ContentType int type = Util.inferContentType(uri, overrideExtension);
        switch (type) {
            case C.TYPE_DASH:
                return new DashMediaSource.Factory(dataSourceFactory)
                        .createMediaSource(uri);
            case C.TYPE_SS:
                return new SsMediaSource.Factory(dataSourceFactory)
                        .createMediaSource(uri);
            case C.TYPE_HLS:
                return new HlsMediaSource.Factory(dataSourceFactory)
                        .createMediaSource(uri);
            case C.TYPE_OTHER:
                return new ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
            default: {
                throw new IllegalStateException("Unsupported type: " + type);
            }
        }
    }

    private void releasePlayer() {
        if (exoPlayer != null) {
            resumePosition = exoPlayer.getCurrentPosition();
            currentWindow = exoPlayer.getCurrentWindowIndex();
            exoPlayer.release();
        }
    }

    private boolean isPlaying() {
        return exoPlayer != null
                && exoPlayer.getPlaybackState() != Player.STATE_ENDED
                && exoPlayer.getPlaybackState() != Player.STATE_IDLE
                && exoPlayer.getPlayWhenReady();
    }

    public boolean mediaIsPlaying() {
        try {
            if (exoPlayer != null) {
                return isPlaying();
            } else {
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public void onAudioFocusChange(int focusState) {

        LogHelper.d(TAG, "onAudioFocusChange. focusChange=", focusState);
        switch (focusState) {
            case AudioManager.AUDIOFOCUS_GAIN:
                mCurrentAudioFocusState = AUDIO_FOCUSED;
                break;
            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                // Audio focus was lost, but it's possible to duck (i.e.: play quietly)
                mCurrentAudioFocusState = AUDIO_NO_FOCUS_CAN_DUCK;
                break;
            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                // Lost audio focus, but will gain it back (shortly), so note whether
                // playback should resume
                mCurrentAudioFocusState = AUDIO_NO_FOCUS_NO_DUCK;
                mPlayOnFocusGain = exoPlayer != null && exoPlayer.getPlayWhenReady();
                break;
            case AudioManager.AUDIOFOCUS_LOSS:
                // Lost audio focus, probably "permanently"
                mCurrentAudioFocusState = AUDIO_NO_FOCUS_NO_DUCK;
                break;
        }

        if (exoPlayer != null) {
            // Update the player state based on the change
            configurePlayerState();
        }
    }

    private void configurePlayerState() {
        LogHelper.d(TAG, "configurePlayerState. mCurrentAudioFocusState=", mCurrentAudioFocusState);
        if (mCurrentAudioFocusState == AUDIO_NO_FOCUS_NO_DUCK) {
            // We don't have audio focus and can't duck, so we have to pause
            pauseMedia();
        } else {
            registerAudioNoisyReceiver();

            if (mCurrentAudioFocusState == AUDIO_NO_FOCUS_CAN_DUCK) {
                // We're permitted to play, but only if we 'duck', ie: play softly
                exoPlayer.setVolume(VOLUME_DUCK);
            } else {
                exoPlayer.setVolume(VOLUME_NORMAL);
            }

            // If we were playing when we lost focus, we need to resume playing.
            if (mPlayOnFocusGain) {
                exoPlayer.setPlayWhenReady(true);
                mPlayOnFocusGain = false;
                buildNotification(PlaybackStatus.PLAYING);
            }
        }
    }

    /**
     * AudioFocus
     */
    private boolean requestAudioFocus() {
        audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
        if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
            //Focus gained
            return true;
        }
        //Could not gain focus
        return false;
    }

    private boolean removeAudioFocus() {
        if (audioManager != null) {
            return AudioManager.AUDIOFOCUS_REQUEST_GRANTED ==
                    audioManager.abandonAudioFocus(this);
        } else {
            return false;
        }
    }

    private void releaseResources(boolean releasePlayer) {
        LogHelper.d(TAG, "releaseResources. releasePlayer=", releasePlayer);

        // Stops and releases player (if requested and available).
        if (releasePlayer && exoPlayer != null) {
            exoPlayer.release();
            exoPlayer.removeListener(this);
            exoPlayer = null;
//            mExoPlayerNullIsStopped = true;
            mPlayOnFocusGain = false;
        }

//        if (mWifiLock.isHeld()) {
//            mWifiLock.release();
//        }
    }

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        super.onTaskRemoved(rootIntent);
        stopSelf();
        removeNotification();

        long duration;
        if (exoPlayer != null) {
            resumePosition = exoPlayer.getCurrentPosition();
            duration = exoPlayer.getDuration();
        } else {
            resumePosition = 0;
            duration = 0L;
        }

        PodcastStorageUtil.getInstance().setShouldAutoPlay(false);

    }

    private void stopMedia() {

        if (exoPlayer == null) return;

        try {
            if (isPlaying()) {

                exoPlayer.stop();
            }


        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void skipToNext() {
        skipForward();
    }

    private void skipToPrevious() {
        skipBackwards();
    }

    private void registerAudioNoisyReceiver() {
        if (!mAudioNoisyReceiverRegistered) {
            registerReceiver(becomingNoisyReceiver, mAudioNoisyIntentFilter);
            mAudioNoisyReceiverRegistered = true;
        }
    }

    private void unregisterAudioNoisyReceiver() {
        if (mAudioNoisyReceiverRegistered) {
            unregisterReceiver(becomingNoisyReceiver);
            mAudioNoisyReceiverRegistered = false;
        }
    }

    /**
     * Handle PhoneState changes
     */
    //Dont think this is needed anymore
//    private void callStateListener() {
//        // Get the telephony manager
//        telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
//        //Starting listening for PhoneState changes
//        phoneStateListener = new PhoneStateListener() {
//            @Override
//            public void onCallStateChanged(int state, String incomingNumber) {
//                switch (state) {
//                    //if at least one call exists or the phone is ringing
//                    //pause the MediaPlayer
//                    case TelephonyManager.CALL_STATE_OFFHOOK:
//                    case TelephonyManager.CALL_STATE_RINGING:
//                        if (exoPlayer != null) {
//                            pauseMedia();
//                            ongoingCall = true;
//
//                        }
//                        break;
//                    case TelephonyManager.CALL_STATE_IDLE:
//                        // Phone idle. Start playing.
//                        if (exoPlayer != null) {
//                            if (ongoingCall) {
//                                ongoingCall = false;
//                                if (PodcastStorageUtil.getInstance().shouldAutoPlay()) {
//                                    resumeMedia();
//                                }
//                            }
//                        }
//                        break;
//                }
//            }
//        };
//        // Register the listener with the telephony manager
//        // Listen for changes to the device call state.
//        telephonyManager.listen(phoneStateListener,
//                PhoneStateListener.LISTEN_CALL_STATE);
//    }

    private void updateMetaData() {
        if (mVideo != null) {
            mediaSession.setMetadata(new MediaMetadataCompat.Builder()
                    .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, albumArt)
                    .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, getString(R.string.app_name))
                    .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, getString(R.string.app_name))
                    .putString(MediaMetadataCompat.METADATA_KEY_TITLE, String.valueOf(Html.fromHtml(mVideo.getTitle())))
                    .build());
        }
    }


    private void buildNotification(PlaybackStatus playbackStatus) {

        /*
          Notification actions -> playbackAction()
           0 -> Play
           1 -> Pause
           2 -> Next track
           3 -> Previous track
         */

        if (mVideo == null) {
            return;
        }

        int notificationAction = R.drawable.ic_pause_small_notif;//needs to be initialized
        PendingIntent play_pauseAction = null;

        //Build a new notification according to the current state of the MediaPlayer
        if (playbackStatus == PlaybackStatus.PLAYING) {
            notificationAction = R.drawable.ic_pause_small_notif;
            //create the pause action
            play_pauseAction = playbackAction(1);
        } else if (playbackStatus == PlaybackStatus.PAUSED) {
            notificationAction = R.drawable.ic_play_small_notif;
            //create the play action
            play_pauseAction = playbackAction(0);
        }

        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(VideoPlayerService.this, "notify_002")
                // Hide the timestamp
                .setShowWhen(false)
                // Set the Notification style
                .setStyle(new androidx.media.app.NotificationCompat.MediaStyle()
                        // Attach our MediaSession token
                        .setMediaSession(mediaSession.getSessionToken())
                        // Show our playback controls in the compat view
                        .setShowActionsInCompactView(0, 1, 2))
                // Set the Notification color

                .setColor(getResources().getColor(R.color.colorPrimary))
                // Set the large and small icons
                .setLargeIcon(albumArt)
                .setSmallIcon(android.R.drawable.stat_sys_headset)
                // Set Notification content information
                .setContentText(getString(R.string.app_name))
                .setContentTitle(Html.fromHtml(mVideo.getTitle()))
                .setContentInfo(getString(R.string.app_name))
                // Add playback actions
                .addAction(R.drawable.ic_skip_back_small_notif, "previous", playbackAction(3))
                .addAction(notificationAction, "pause", play_pauseAction)
                .addAction(R.drawable.ic_skip_forward_small_notif, "next", playbackAction(2));

        NotificationManager mNotificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);


        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("notify_002",
                    "The Anfield Wrap video control channel",
                    NotificationManager.IMPORTANCE_LOW);
            mNotificationManager.createNotificationChannel(channel);
        }

        Notification notification = notificationBuilder.build();

        mNotificationManager.notify(NOTIFICATION_ID, notification);


        startForeground(NOTIFICATION_ID, notification);
    }

    private PendingIntent playbackAction(int actionNumber) {
        Intent playbackAction = new Intent(this, VideoPlayerService.class);
        switch (actionNumber) {
            case 0:
                // Play
                playbackAction.setAction(ACTION_PLAY);
                return PendingIntent.getService(this, actionNumber, playbackAction, 0);
            case 1:
                // Pause
                playbackAction.setAction(ACTION_PAUSE);
                return PendingIntent.getService(this, actionNumber, playbackAction, 0);
            case 2:
                // Next track
                playbackAction.setAction(ACTION_NEXT);
                return PendingIntent.getService(this, actionNumber, playbackAction, 0);
            case 3:
                // Previous track
                playbackAction.setAction(ACTION_PREVIOUS);
                return PendingIntent.getService(this, actionNumber, playbackAction, 0);
            default:
                break;
        }
        return null;
    }

    private void removeNotification() {
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.cancel(NOTIFICATION_ID);
    }

    private void handleIncomingActions(Intent playbackAction) {
        if (playbackAction == null || playbackAction.getAction() == null) return;

        String actionString = playbackAction.getAction();
        if (actionString.equalsIgnoreCase(ACTION_PLAY)) {
            transportControls.play();
        } else if (actionString.equalsIgnoreCase(ACTION_PAUSE)) {
            transportControls.pause();
        } else if (actionString.equalsIgnoreCase(ACTION_NEXT)) {
            transportControls.skipToNext();
        } else if (actionString.equalsIgnoreCase(ACTION_PREVIOUS)) {
            transportControls.skipToPrevious();
        } else if (actionString.equalsIgnoreCase(ACTION_STOP)) {
            transportControls.stop();
        }
    }

    public MediaSessionManager getMediaSessionManager() throws RemoteException {
        if (mediaSessionManager == null) {
            initMediaSession();
        }
        return mediaSessionManager;
    }

    public MediaSessionCompat getMediaSession() throws RemoteException {
        if (mediaSession == null) {
            initMediaSession();
        }
        return mediaSession;
    }

    public MediaControllerCompat.TransportControls getTransportControls() throws RemoteException {
        if (transportControls == null) {
            initMediaSession();
        }
        return transportControls;
    }

    public long getDuration() {
        try {

            return exoPlayer.getDuration();

        } catch (Exception e) {
            e.printStackTrace();
            return 0L;
        }
    }

    public Long getElapsedTime() {
        try {
            if (exoPlayer != null && mVideo != null) {
                resumePosition = exoPlayer.getCurrentPosition();
                return exoPlayer.getCurrentPosition();
            } else {
                return 0L;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return 0L;
        }
    }

    public void skipForward() {
        if (exoPlayer != null && mVideo != null) {
            long newDuration = getElapsedTime() + 15000;

            if (newDuration > getDuration()) {
                newDuration = getDuration() - 1;
            }
            transportControls.seekTo(newDuration);
        }
    }

    public void skipBackwards() {
        if (exoPlayer != null && mVideo != null) {
            long newDuration = getElapsedTime() - 15000;

            if (newDuration < 0) {
                newDuration = 0L;
            }
            transportControls.seekTo(newDuration);
        }
    }


    private void resumeMedia() {

        if (exoPlayer != null) {
            buildNotification(PlaybackStatus.PLAYING);
            PodcastStorageUtil.getInstance().setShouldAutoPlay(true);
            if (!isPlaying()) {
                exoPlayer.seekTo(resumePosition);
                exoPlayer.setPlayWhenReady(true);
                exoPlayer.getPlaybackState();
            }
        }
    }

    private void pauseMedia() {
        buildNotification(PlaybackStatus.PAUSED);

        // Pause player and cancel the 'foreground service' state.
        if (exoPlayer != null) {
            resumePosition = exoPlayer.getCurrentPosition();
            exoPlayer.setPlayWhenReady(false);
//            if (activePodcast != null) {
//                storeAudioPosition(activePodcast.getPostId(), resumePosition, exoPlayer.getDuration());
//            }
        }
        // While paused, retain the player instance, but give up audio focus.
        releaseResources(false);
        unregisterAudioNoisyReceiver();
        PodcastStorageUtil.getInstance().setShouldAutoPlay(false);

    }

    @Override
    public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
    }

    @Override
    public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
    }

    @Override
    public void onLoadingChanged(boolean isLoading) {
    }

    @Override
    public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {

        if (playbackState == Player.STATE_ENDED) {
            albumArt = null;

            stopMedia();
            releasePlayer();

            removeNotification();
            PodcastStorageUtil.getInstance().setShouldAutoPlay(false);
            //stop the service
            stopSelf();
        } else if (playbackState == Player.STATE_READY && playWhenReady) {
            PodcastStorageUtil.getInstance().setShouldAutoPlay(true);
        }
    }

    @Override
    public void onRepeatModeChanged(int repeatMode) {

    }

    @Override
    public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {

    }

    @Override
    public void onPlayerError(ExoPlaybackException error) {
        error.printStackTrace();
    }

    @Override
    public void onPositionDiscontinuity(int reason) {

    }

    @Override
    public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {

    }

    @Override
    public void onSeekProcessed() {

    }

    /**
     * MediaSession and Notification actions
     */
    private void initMediaSession() throws RemoteException {

        if (mediaSessionManager != null) return; //mediaSessionManager exists

        mediaSessionManager = (MediaSessionManager) getSystemService(Context.MEDIA_SESSION_SERVICE);
        // Create a new MediaSession

        mediaSession = new MediaSessionCompat(getApplicationContext(),
                MEDIA_SESSION_ID);//, mediaButtonReceiver,  null);
        //Get MediaSessions transport controls
        transportControls = mediaSession.getController().getTransportControls();
        //set MediaSession -> ready to receive media commands
        //indicate that the MediaSession handles transport control commands
        // through its MediaSessionCompat.Callback.
        mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
        mediaSession.setActive(true);

        //Set mediaSession's MetaData
        updateMetaData();


        // Attach Callback to receive MediaSession updates
        mediaSession.setCallback(new MediaSessionCompat.Callback() {
            // Implement callbacks
            @Override
            public void onPlay() {
                super.onPlay();

                resumeMedia();
                buildNotification(PlaybackStatus.PLAYING);
            }

            @Override
            public void onPause() {
                super.onPause();

                pauseMedia();
            }

            @Override
            public void onSkipToNext() {
                super.onSkipToNext();

                skipToNext();
                updateMetaData();
                buildNotification(PlaybackStatus.PLAYING);
            }

            @Override
            public void onSkipToPrevious() {
                super.onSkipToPrevious();

                skipToPrevious();
                updateMetaData();
                buildNotification(PlaybackStatus.PLAYING);
            }

            @Override
            public void onStop() {
                super.onStop();
                removeNotification();
                //Stop the service

                stopMedia();
                stopSelf();

            }


            @Override
            public boolean onMediaButtonEvent(Intent mediaButtonEvent) {

                try {
                    Log.d("onMediaButtonEvent", "onMediaButtonEvent called: " + mediaButtonEvent);
                    KeyEvent ke = mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
                    if (ke != null && ke.getAction() == KeyEvent.ACTION_DOWN) {
                        int keyCode = ke.getKeyCode();

                        Log.d("onMediaButtonEvent", "onMediaButtonEvent called: " + keyCode);

                        if (keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {
                            pauseMedia();
                        } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {
                            resumeMedia();
                        } else if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK) {
                            if (isPlaying()) {
                                pauseMedia();
                            } else {
                                if (exoPlayer != null) {
                                    resumeMedia();
                                }
                            }
                        }
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }

                return super.onMediaButtonEvent(mediaButtonEvent);
            }

            @Override
            public void onSeekTo(long position) {
                super.onSeekTo(position);
                resumePosition = position;

                if (exoPlayer != null) {
                    exoPlayer.seekTo(resumePosition);
                    resumeMedia();
                }
            }
        });
    }

    /**
     * Service Binder
     */
    public class LocalBinder extends Binder {
        public VideoPlayerService getService() {
            // Return this instance of LocalService so clients can call public methods
            return VideoPlayerService.this;
        }
    }


}
