package com.moiseum.wolnelektury.view.player;

import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.media.MediaBrowserCompat;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.util.Log;

import com.moiseum.wolnelektury.base.WLApplication;
import com.moiseum.wolnelektury.base.mvp.FragmentPresenter;
import com.moiseum.wolnelektury.connection.models.BookDetailsModel;
import com.moiseum.wolnelektury.connection.models.BookModel;
import com.moiseum.wolnelektury.storage.BookStorage;
import com.moiseum.wolnelektury.view.player.service.AudiobookLibrary;
import com.moiseum.wolnelektury.view.player.service.AudiobookService;
import com.moiseum.wolnelektury.view.player.service.MediaBrowserHelper;

import java.util.List;
import java.util.Locale;

/**
 * Created by Piotr Ostrowski on 22.05.2018.
 */
public class PlayerPresenter extends FragmentPresenter<PlayerView> {

	private final BookDetailsModel book;
	private final BookModel storedBook;

	private final BookStorage storage = WLApplication.getInstance().getBookStorage();
	private MediaBrowserHelper mMediaBrowserHelper;
	private boolean mIsPlaying;

	/**
	 * Customize the connection to our {@link android.support.v4.media.MediaBrowserServiceCompat}
	 * and implement our app specific desires.
	 */
	private class MediaBrowserConnection extends MediaBrowserHelper {
		private MediaBrowserConnection(Context context) {
			super(context, AudiobookService.class);
		}

		@Override
		protected void onChildrenLoaded(@NonNull String parentId,
		                                @NonNull List<MediaBrowserCompat.MediaItem> children) {
			super.onChildrenLoaded(parentId, children);

			final MediaControllerCompat mediaController = getMediaController();
			mediaController.getTransportControls().sendCustomAction(AudiobookService.ACTION_CLEAR_PLAYLIST, null);

			AudiobookLibrary.createAudiobookMetadata(book);
			for (final MediaBrowserCompat.MediaItem mediaItem : AudiobookLibrary.getMediaItems()) {
				mediaController.addQueueItem(mediaItem.getDescription());
			}

			// Call prepare now so pressing play just works.
			mediaController.getTransportControls().prepare();
			if (storedBook != null) {
				mediaController.getTransportControls().skipToQueueItem(storedBook.getCurrentAudioChapter());
				mediaController.getTransportControls().pause();
			}
		}
	}

	/**
	 * Implementation of the {@link MediaControllerCompat.Callback} methods we're interested in.
	 * <p>
	 * Here would also be where one could override
	 * {@code onQueueChanged(List<MediaSessionCompat.QueueItem> queue)} to get informed when items
	 * are added or removed from the queue. We don't do this here in order to keep the UI
	 * simple.
	 */
	private class PlayerMediaControllerCallback extends MediaControllerCompat.Callback {
		@Override
		public void onPlaybackStateChanged(PlaybackStateCompat playbackState) {
			if (playbackState != null) {
				if (playbackState.getState() == PlaybackStateCompat.STATE_ERROR) {
					getView().onPlayerError();
				}

				mIsPlaying = playbackState.getState() == PlaybackStateCompat.STATE_PLAYING;
				getView().setPlayButtonState(mIsPlaying);

				if (mIsPlaying && playbackState.getExtras() != null) {
					int total = playbackState.getExtras().getInt(AudiobookService.EXTRA_PLAYBACK_TOTAL);
					getView().setTrackDuration(total, getCurrentTimerText(total));
				}
			}
		}

		@Override
		public void onMetadataChanged(MediaMetadataCompat mediaMetadata) {
			if (mediaMetadata == null) {
				return;
			}
			if (!book.getAudiobookFilesUrls().contains(mediaMetadata.getString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID))) {
				return;
			}

			int currentChapter = (int) mediaMetadata.getLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER);
			if (storedBook != null) {
				storedBook.setCurrentAudioChapter(currentChapter);
				storage.update(storedBook);
			}

			String chapterTitle = mediaMetadata.getString(MediaMetadataCompat.METADATA_KEY_TITLE);
			getView().setTrackTexts(chapterTitle, currentChapter);
		}

		@Override
		public void onExtrasChanged(Bundle extras) {
			if (extras.containsKey(AudiobookService.EXTRA_PLAYBACK_CURRENT)) {
				int position = extras.getInt(AudiobookService.EXTRA_PLAYBACK_CURRENT);
				getView().setTrackPosition(position, getCurrentTimerText(position));
			}
			if (extras.containsKey(AudiobookService.EXTRA_PLAYBACK_TOTAL)) {
				int total = extras.getInt(AudiobookService.EXTRA_PLAYBACK_TOTAL);
				getView().setTrackDuration(total, getCurrentTimerText(total));
			}
		}

		@Override
		public void onSessionDestroyed() {
			super.onSessionDestroyed();
		}

		@Override
		public void onQueueChanged(List<MediaSessionCompat.QueueItem> queue) {
			super.onQueueChanged(queue);
		}
	}

	PlayerPresenter(BookDetailsModel book, String slug, PlayerView view, Context context) {
		super(view);
		this.book = book;
		this.storedBook = storage.find(slug);
		mMediaBrowserHelper = new MediaBrowserConnection(context);
		mMediaBrowserHelper.registerCallback(new PlayerMediaControllerCallback());
	}

	@Override
	public void onStart() {
		super.onStart();
		mMediaBrowserHelper.onStart();
	}

	@Override
	public void onStop() {
		super.onStop();
		mMediaBrowserHelper.onStop();
	}

	public void playOrPause(boolean pauseCall) {
		if (mIsPlaying) {
			mMediaBrowserHelper.getTransportControls().pause();
		} else {
			mMediaBrowserHelper.getTransportControls().play();
		}
	}

	public void changeChapter(boolean next) {
		if (next) {
			mMediaBrowserHelper.getTransportControls().skipToNext();
		} else {
			mMediaBrowserHelper.getTransportControls().skipToPrevious();
		}
	}

	public void seekToButton(boolean forward) {
		if (forward) {
			mMediaBrowserHelper.getTransportControls().fastForward();
		} else {
			mMediaBrowserHelper.getTransportControls().rewind();
		}
	}

	public void seekTo(int userSelectedPosition) {
		mMediaBrowserHelper.getTransportControls().seekTo(userSelectedPosition);
	}

	public String getCurrentTimerText(int currentPosition) {
		StringBuilder sb = new StringBuilder();
		int minutes = (currentPosition % (1000 * 60 * 60)) / (1000 * 60);
		int seconds = ((currentPosition % (1000 * 60 * 60)) % (1000 * 60) / 1000);
		if (currentPosition > (1000 * 60 * 60)) {
			int hours = (currentPosition / (1000 * 60 * 60));
			sb.append(String.format(Locale.getDefault(), "%01d", hours));
			sb.append(":");
		}
		sb.append(String.format(Locale.getDefault(), "%02d", minutes));
		sb.append(":");
		sb.append(String.format(Locale.getDefault(), "%02d", seconds));
		return sb.toString();
	}
}
